perm filename CLOOPS.MSG[COM,LSP]4 blob
sn#841466 filedate 1987-06-15 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00141 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00022 00002
C00023 00003 ∂17-Apr-87 1011 @ALDERAAN.SCRC.Symbolics.COM:jlb@WAIKATO.S4CC.Symbolics.COM "Object" System
C00026 00004 ∂17-Apr-87 1149 Moon@ALDERAAN.SCRC.Symbolics.COM Re: Object creation discussion (at last!)
C00037 00005 ∂17-Apr-87 1244 Moon@STONY-BROOK.SCRC.Symbolics.COM (long) CLOS Declaration Proposal Text
C00041 00006 ∂20-Apr-87 1331 DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET Re: Object creation discussion (at last!)
C00050 00007 ∂20-Apr-87 1355 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Object creation discussion (at last!)
C00053 00008 ∂20-Apr-87 1449 DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET Re: Object creation discussion (at last!)
C00055 00009 ∂21-Apr-87 0812 DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET Re: Object creation discussion (at last!)
C00059 00010 ∂21-Apr-87 1049 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Object creation discussion (at last!)
C00063 00011 ∂22-Apr-87 1348 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
C00073 00012 ∂22-Apr-87 1448 Gregor.pa@Xerox.COM CL types --> classes
C00076 00013 ∂22-Apr-87 1533 Pavel.pa@Xerox.COM Re: CL types --> classes
C00078 00014 ∂22-Apr-87 1637 Gregor.pa@Xerox.COM note about clos instance disjointness
C00080 00015 ∂22-Apr-87 1639 Gregor.pa@Xerox.COM funcallable-standard-class
C00082 00016 ∂22-Apr-87 1729 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
C00090 00017 ∂23-Apr-87 0953 kempf%hplabsc@hplabs.HP.COM Re: CLOS Type Cleanup
C00092 00018 ∂23-Apr-87 1225 kempf%hplabsc@hplabs.HP.COM Re: (long) CLOS Declaration Proposal Text
C00099 00019 ∂23-Apr-87 1249 kempf%hplabsc@hplabs.HP.COM Re: Object Creation Discussion (at last!)
C00112 00020 ∂23-Apr-87 1456 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: CLOS Declaration Proposal
C00114 00021 ∂23-Apr-87 1722 kempf%hplabsc@hplabs.HP.COM Re: CLOS Declaration Proposal
C00116 00022 ∂23-Apr-87 2020 Gregor.pa@Xerox.COM Re: Object Creation Discussion (at last!)
C00122 00023 ∂23-Apr-87 2132 Moon@STONY-BROOK.SCRC.Symbolics.COM CL types --> classes
C00127 00024 ∂26-Apr-87 2231 Moon@STONY-BROOK.SCRC.Symbolics.COM Object creation discussion (at last!)
C00152 00025 ∂27-Apr-87 1329 DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET Re: Object creation discussion (at last!)
C00166 00026 ∂29-Apr-87 1836 Moon@STONY-BROOK.SCRC.Symbolics.COM Object creation discussion (at last!)
C00168 00027 ∂06-May-87 0936 kempf%hplabsc@hplabs.HP.COM Printing Objects
C00170 00028 ∂06-May-87 1142 DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET Re: Printing Objects
C00173 00029 ∂06-May-87 1304 kempf%hplabsc@hplabs.HP.COM Re: Printing Objects
C00176 00030 ∂06-May-87 2024 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Printing Objects
C00182 00031 ∂06-May-87 2202 Masinter.pa@Xerox.COM Re: Printing Objects
C00185 00032 ∂06-May-87 2235 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Printing Objects
C00190 00033 ∂07-May-87 0851 kempf%hplabsc@hplabs.HP.COM Re: Printing Objects
C00196 00034 ∂13-May-87 1131 kempf%hplabsc@hplabs.HP.COM Object Printing Discussion
C00206 00035 ∂13-May-87 1323 Gregor.pa@Xerox.COM Re: Object Printing Discussion
C00211 00036 ∂13-May-87 1444 DLW@ALDERAAN.SCRC.Symbolics.COM Object Printing Discussion
C00215 00037 ∂14-May-87 1322 kempf%hplabsc@hplabs.HP.COM Re: Printing Objects
C00220 00038 ∂15-May-87 1110 Gregor.pa@Xerox.COM optimization versus constructors
C00224 00039 ∂15-May-87 1240 kempf%hplabsc@hplabs.HP.COM Why is MAKE-INSTANCE not generic?
C00226 00040 ∂15-May-87 1315 kempf%hplabsc@hplabs.HP.COM Re: Why in MAKE-INSTANCE not generic?
C00228 00041 ∂15-May-87 1648 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Why in MAKE-INSTANCE not generic?
C00230 00042 ∂15-May-87 1715 Moon@STONY-BROOK.SCRC.Symbolics.COM optimization versus constructors
C00234 00043 ∂20-May-87 1934 Pavel.pa@Xerox.COM CLOS vs. subtypes of FLOAT
C00246 00044 ∂21-May-87 1228 Pavel.pa@Xerox.COM Re: CLOS vs. subtypes of FLOAT
C00248 00045 ∂21-May-87 1227 Masinter.pa@Xerox.COM Re: CLOS vs. subtypes of FLOAT
C00250 00046 ∂21-May-87 1338 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: CLOS vs. subtypes of FLOAT
C00253 00047 ∂21-May-87 1909 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
C00270 00048 ∂22-May-87 0627 @RELAY.CS.NET:DUSSUD%Jenner@TI-CSL.CSNET Re: CLOS vs. subtypes of FLOAT
C00275 00049 ∂22-May-87 0725 DLW@ALDERAAN.SCRC.Symbolics.COM Re: Object creation discussion (at last!)
C00279 00050 ∂22-May-87 1002 kempf%hplabsc@hplabs.HP.COM Arguments to CALL-NEXT-METHOD
C00281 00051 ∂22-May-87 1116 Gregor.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00284 00052 ∂22-May-87 1635 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
C00291 00053 ∂23-May-87 0414 kempf%hplabsc@hplabs.HP.COM Re: Arguments to CALL-NEXT-METHOD
C00293 00054 ∂23-May-87 1622 Bobrow.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00296 00055 ∂23-May-87 1839 Bobrow.pa@Xerox.COM Object creation discussion (at last!)
C00313 00056 ∂25-May-87 0816 kempf%hplabsc@hplabs.HP.COM Re: Arguments to CALL-NEXT-METHOD
C00316 00057 ∂25-May-87 1754 masinter.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00318 00058 ∂25-May-87 1818 Bobrow.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00320 00059 ∂26-May-87 1724 Masinter.pa@Xerox.COM Re: CLOS vs. subtypes of FLOAT
C00323 00060 ∂26-May-87 2253 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Arguments to CALL-NEXT-METHOD
C00329 00061 ∂26-May-87 2259 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Object creation discussion (at last!)
C00338 00062 ∂26-May-87 2335 kempf%hplabsc@hplabs.HP.COM Re: CLOS vs. subtypes of FLOAT
C00340 00063 ∂27-May-87 0803 Bobrow.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00344 00064 ∂27-May-87 1057 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Arguments to CALL-NEXT-METHOD
C00346 00065 ∂27-May-87 1122 RPG OOPSLA Lisp and Object-Oriented Programming Workshop
C00348 00066 ∂27-May-87 1124 RPG Floats
C00362 00067 ∂27-May-87 1331 Masinter.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00365 00068 ∂27-May-87 1604 Gregor.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00367 00069 ∂27-May-87 1604 Bobrow.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00369 00070 ∂27-May-87 1605 Gregor.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00373 00071 ∂27-May-87 1753 Moon@SAPSUCKER.SCRC.Symbolics.COM Re: Arguments to CALL-NEXT-METHOD
C00375 00072 ∂27-May-87 1909 kahn.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00377 00073 ∂27-May-87 1910 Gregor.pa@Xerox.COM OK, I stand corrected
C00381 00074 ∂27-May-87 1910 Bobrow.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00384 00075 ∂27-May-87 1910 Gregor.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00386 00076 ∂28-May-87 0413 kempf%hplabsc@hplabs.HP.COM Re: Arguments to CALL-NEXT-METHOD
C00388 00077 ∂28-May-87 0804 kempf%hplabsc@hplabs.HP.COM Re: Arguments to CALL-NEXT-METHOD
C00390 00078 ∂28-May-87 0856 kempf%hplabsc@hplabs.HP.COM Re: Floats
C00396 00079 ∂28-May-87 1158 Masinter.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00398 00080 ∂28-May-87 1251 kempf%hplabsc@hplabs.HP.COM Re: Arguments to CALL-NEXT-METHOD
C00400 00081 ∂28-May-87 1458 Bobrow.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00402 00082 ∂28-May-87 1511 kempf%hplabsc@hplabs.HP.COM Re: Arguments to CALL-NEXT-METHOD
C00404 00083 ∂28-May-87 1532 Gregor.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
C00406 00084 ∂28-May-87 2159 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Arguments to CALL-NEXT-METHOD
C00409 00085 ∂29-May-87 1418 Moon@STONY-BROOK.SCRC.Symbolics.COM Object creation discussion (at last!)
C00423 00086 ∂29-May-87 1430 Moon@STONY-BROOK.SCRC.Symbolics.COM Object creation discussion (at last!)
C00440 00087 ∂29-May-87 1818 Bobrow.pa@Xerox.COM Re: Object creation discussion (at last!)
C00445 00088 ∂29-May-87 2300 RPG Object Creation (at last!)
C00447 00089 ∂31-May-87 1313 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
C00456 00090 ∂31-May-87 1439 masinter.pa@Xerox.COM Re: Object Creation (at last!)
C00458 00091 ∂31-May-87 1644 RPG Object creation discussion (at last!)
C00482 00092 ∂01-Jun-87 2132 Moon@STONY-BROOK.SCRC.Symbolics.COM object / cleanup subcommittee interaction
C00484 00093 ∂02-Jun-87 1029 RPG object / cleanup subcommittee interaction
C00486 00094 ∂02-Jun-87 1203 Bobrow.pa@Xerox.COM Re: object / cleanup subcommittee interaction
C00488 00095 ∂02-Jun-87 1642 kempf%hplabsc@hplabs.HP.COM Re: object / cleanup subcommittee interaction
C00490 00096 ∂02-Jun-87 2022 Bobrow.pa@Xerox.COM Re: Object creation discussion (at last!)
C00496 00097 ∂03-Jun-87 1220 Bobrow.pa@Xerox.COM Re: Floats
C00500 00098 ∂03-Jun-87 1221 Gregor.pa@Xerox.COM Re: object / cleanup subcommittee interaction
C00502 00099 ∂03-Jun-87 1455 kempf%hplabsc@hplabs.HP.COM Re: object / cleanup subcommittee interaction
C00504 00100 ∂03-Jun-87 1709 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
C00521 00101 ∂03-Jun-87 2020 RPG My Message of May 29
C00524 00102 ∂04-Jun-87 1004 kempf%hplabsc@hplabs.HP.COM SETF- method names
C00527 00103 ∂04-Jun-87 1525 kempf%hplabsc@hplabs.HP.COM Re: object creation / initialization discussion
C00532 00104 ∂05-Jun-87 2359 Masinter.pa@Xerox.COM Re: object / cleanup subcommittee interaction
C00539 00105 ∂06-Jun-87 1219 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
C00546 00106 ∂06-Jun-87 1350 RPG Order of Initialization
C00553 00107 ∂06-Jun-87 1624 kempf%hplabsc@hplabs.HP.COM Re: Order of Initialization
C00558 00108 ∂06-Jun-87 1636 RPG Order of Initialization
C00559 00109 ∂08-Jun-87 1907 Bobrow.pa@Xerox.COM Open Issues in 87-002
C00566 00110 ∂09-Jun-87 0719 skeene@STONY-BROOK.SCRC.Symbolics.COM Open Issues in 87-002
C00568 00111 ∂09-Jun-87 0803 kempf%hplabsc@hplabs.HP.COM I. Formal Specification of Gen. Fcn. Invocation
C00575 00112 ∂09-Jun-87 0804 kempf%hplabsc@hplabs.HP.COM II. Formal Specification of Gen. Fcn. Invocation
C00580 00113 ∂09-Jun-87 0804 kempf%hplabsc@hplabs.HP.COM III. Formal Specification of Gen. Fcn. Invocation
C00586 00114 ∂09-Jun-87 0805 kempf%hplabsc@hplabs.HP.COM IV. Formal Specification of Gen. Fcn. Invocation
C00595 00115 ∂09-Jun-87 0854 kempf%hplabsc@hplabs.HP.COM Re: Order of Initialization
C00598 00116 ∂09-Jun-87 0934 kempf%hplabsc@hplabs.HP.COM Re: Open Issues in 87-002
C00607 00117 ∂09-Jun-87 1008 kahn.pa@Xerox.COM Re: Open Issues in 87-002
C00609 00118 ∂09-Jun-87 1035 Bobrow.pa@Xerox.COM Re: Open Issues in 87-002
C00611 00119 ∂09-Jun-87 1050 kempf%hplabsc@hplabs.HP.COM Re: Open Issues in 87-002
C00613 00120 ∂09-Jun-87 1104 Bobrow.pa@Xerox.COM Re: Order of Initialization
C00617 00121 ∂09-Jun-87 1136 Bobrow.pa@Xerox.COM Re: I. Formal Specification of Gen. Fcn. Invocation
C00622 00122 ∂09-Jun-87 1743 @RELAY.CS.NET:DUSSUD%Jenner@TI-CSL.CSNET Re: Object creation discussion (at last!)
C00628 00123 ∂09-Jun-87 1819 Moon@STONY-BROOK.SCRC.Symbolics.COM SETF- method names
C00633 00124 ∂09-Jun-87 1832 Moon@STONY-BROOK.SCRC.Symbolics.COM object / cleanup subcommittee interaction
C00636 00125 ∂09-Jun-87 1852 Moon@STONY-BROOK.SCRC.Symbolics.COM SETF- method names
C00642 00126 ∂09-Jun-87 1921 Moon@STONY-BROOK.SCRC.Symbolics.COM object / cleanup subcommittee interaction
C00648 00127 ∂09-Jun-87 2044 Moon@STONY-BROOK.SCRC.Symbolics.COM I. Formal Specification of Gen. Fcn. Invocation
C00652 00128 ∂09-Jun-87 2234 kempf%hplabsc@hplabs.HP.COM Re: SETF- method names
C00655 00129 ∂09-Jun-87 2349 Masinter.pa@Xerox.COM Re: object / cleanup subcommittee interaction
C00657 00130 ∂10-Jun-87 0934 kempf%hplabsc@hplabs.HP.COM Re: I. Formal Specification of Gen. Fcn. Invocation
C00672 00131 ∂10-Jun-87 1006 RPG CLOS Document
C00673 00132 ∂10-Jun-87 1114 skeene@STONY-BROOK.SCRC.Symbolics.COM Concepts chapter on standard type classes
C00681 00133 ∂10-Jun-87 1117 skeene@STONY-BROOK.SCRC.Symbolics.COM Design Rationale section on standard type classes
C00692 00134 ∂10-Jun-87 1412 Moon@SAPSUCKER.SCRC.Symbolics.COM Re: I. Formal Specification of Gen. Fcn. Invocation
C00694 00135 ∂10-Jun-87 1627 Bobrow.pa@Xerox.COM Re: SETF- method names
C00697 00136 ∂10-Jun-87 2132 Moon@STONY-BROOK.SCRC.Symbolics.COM Object Creation Discussion
C00699 00137 ∂10-Jun-87 2338 RPG
C00703 00138 ∂11-Jun-87 0746 kempf%hplabsc@hplabs.HP.COM Re: SETF- method names
C00705 00139 ∂11-Jun-87 0819 kempf%hplabsc@hplabs.HP.COM Re: Order of Initialization
C00710 00140 ∂11-Jun-87 1120 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: SETF- method names
C00715 00141 ∂11-Jun-87 1243 kempf%hplabsc@hplabs.HP.COM Re: SETF- method names
C00719 ENDMK
C⊗;
∂17-Apr-87 1011 @ALDERAAN.SCRC.Symbolics.COM:jlb@WAIKATO.S4CC.Symbolics.COM "Object" System
Received: from [192.10.41.109] by SAIL.STANFORD.EDU with TCP; 17 Apr 87 10:00:37 PDT
Received: from FLYING-DOVE.SCRC.Symbolics.COM by ALDERAAN.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 72959; Fri 17-Apr-87 13:00:56 EDT
Date: Fri, 17 Apr 87 13:01 EDT
From: Jonathan L. Balgley <jlb@WAIKATO.S4CC.Symbolics.COM>
Subject: "Object" System
To: common-lisp-object-system@sail.stanford.edu
Message-ID: <870417130124.4.JLB@FLYING-DOVE.SCRC.Symbolics.COM>
Hi! I've read the draft version of CLOS standard and gave my comments
through Symbolics' other representatives. But I have one question: Why
is it called the "Common Lisp Object System"?
I understand the desire to be related to the term "object-oriented", but
pure Common Lisp could already be called an "object system". Indeed,
CLtL dedicates an entire chapter (number 2, "Data Types") to discussing
the "variety of types of data objects". I believe that the name will
cause unnecessary confusion when trying to describe the facilities that
CLOS provides over pure Common Lisp. I can hear CL beginners now: "OK,
you've convinced me that conses and symbols are objects. How does that
relate to the Common Lisp Object System?"
So, have other names been proposed and turned down? Is this name
finalized or will you take other suggestions? If you will, here's my
idea for a name: "CL Generic Structure System". Another one, that Sonya
Keene proposed, was "Classes".
At the very least, I hope that the "Design Rationale" chapter will
briefly mention why it's named what it is. Thanks for listening.
∂17-Apr-87 1149 Moon@ALDERAAN.SCRC.Symbolics.COM Re: Object creation discussion (at last!)
Received: from [192.10.41.109] by SAIL.STANFORD.EDU with TCP; 17 Apr 87 11:49:33 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by ALDERAAN.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 73015; Fri 17-Apr-87 14:49:44 EDT
Date: Fri, 17 Apr 87 14:49 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: Object creation discussion (at last!)
To: Common-Lisp-Object-System@SAIL.STANFORD.EDU
In-Reply-To: <2754594256-919057@Jenner>
Message-ID: <870417144911.9.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Thu, 16 Apr 87 16:04:16 CDT
From: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
Thanks for the comments. I hope the others will comment as well (but
I'm certainly willing to wait a few days).
If multiple initargs that fill the same slot are supplied, which value ends up
in the slot is indeterminate.
In what sense do you mean "indeterminate"? Do you mean "defined to be
one of those values, but not defined as to which of them", such that it
would be legal to use a random number generator to decide?
Yes. "which value" should be "which of those values". I certainly won't complain
if someone proposes a determinate action here instead.
We could check, at run time for make-instance that two initargs that fill
the same slot are not getting a value.
For the constructors, we can check at compile time that they don't specify in
their lambda list two initargs filling the same slot. This would be a
restriction for constructors.
Those are good ideas. I agree with the constructor one. I'm not so sure about
the make-instance one, because I just noticed that Common Lisp allows duplicate
keyword arguments in a function call and mandates that the leftmost argument
prevails. One could argue that this should extend to arguments that have different
names but fill the same slot.
I was concerned about the speed of a runtime check either to do what you
(Patrick) suggested, or to do what I just mentioned above. However,
after consulting our implementation I see that it is easy to do,
although we are not currently using the mechanism to address the issue
of multiple initargs filling the same slot. Briefly, you detect at
compile time (or the first time a class is instantiated) that there are
multiple possible initargs, and then you assign a bit in a bit mask to
record whether the given slot has been filled. If you see an initarg
that fills a slot whose bit is already set, you either ignore it
(leftmost duplicate prevails) or check what keyword was used the
previous time (signal an error except in the case where Common Lisp says
the leftmost duplicate prevails).
Given all this, I added the following to my proposal (philosophy section):
>> What if multiple initargs that fill the same slot are supplied?
If the same initarg is given more than once in the arguments to make-instance,
the leftmost occurrence prevails, as required by Common Lisp.
If two different initargs that fill the same slot are given in the arguments
to make-instance, the leftmost occurrence prevails (alternatively we could
make this an error, but I think it's simpler to treat it the same as two
occurrences of the same initarg).
A :constructor option whose lambda-list has more than one parameter that
fills a single slot signals an error, whether or not the parameter names
are eq (see proposal below for how it is possible for non-eq parameters
to fill the same slot).
I also added the following related clarification:
When :default-initargs defaults an initarg that
fills a slot, it is treated the same as an :initform slot-option for purposes
of inheritance (note well: the class that specifies the :default-initargs
may not know whether the initarg fills a slot or not, and indeed this may
depend on which subclass of that class we are dealing with). If a single
class specifies more than one default value for a single slot, via
:default-initargs or :initform or both, an error is signalled.
Is this agreeable?
Initargs don't have to be keywords, but the entire object creation might not work
very well if any of initargs is not a keyword:
In common Lisp, :allow-other-keys T works only for keyword value pairs. We would
have to slightly change its meaning for make-instance.
In practice this is probably implemented by calling all of the
initialize-instance methods with all of the initargs and automatically adding
&allow-other-keys to the lambda-list in defmethod.
This won't work if there is an initarg which is not a key. The methods that
can be called during object creation (like those on allocate-instance) would be
easier to code if they knew that they would get keyword-value pairs. (if I
understand correctly, those methods would get all the arguments supplied to
make-instance, right?)
I can't understand what you're getting at here. Could you send a follow-up
message this is more explicit?
>> Can step 2 return an existing object instead of allocating storage,
aborting the remaining steps?
No, to do "interning" you must build a higher-level interface around
make-instance. Make-instance always makes.
I am wondering if you propose to enforce this. What if somebody defines an
:around method for ALLOCATE-INSTANCE and does not call-next-method but returns
an interned object instead ? Is it an error?
I don't see how it would be possible to enforce a restriction that the value
returned by ALLOCATE-INSTANCE is not EQ to any other object in the world.
However, note that in your example the value returned by ALLOCATE-INSTANCE
is going to have every one of its slots stored into, and is going to have
its INITIALIZE-INSTANCE methods run, so the effect might not be what the user
intended. What I was really getting at with my philosophy question is "should
a way be provided for the metaclass to be able to completely bypass the
entire action of MAKE-INSTANCE?" and my answer to that is "no". In my file
copy of the proposal I changed this section to the following:
>> Can step 2 return an existing object instead of allocating storage,
aborting the remaining steps?
Step 2 can return anything it wants, but the remaining steps are still
executed. To do "interning" you must build a higher-level interface around
make-instance; make-instance always makes. No way is provided for the
metaclass to be able to completely bypass the entire action of MAKE-INSTANCE.
Is this agreeable?
∂17-Apr-87 1244 Moon@STONY-BROOK.SCRC.Symbolics.COM (long) CLOS Declaration Proposal Text
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 17 Apr 87 12:44:29 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 118986; Fri 17-Apr-87 15:29:48 EDT
Date: Fri, 17 Apr 87 15:29 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: (long) CLOS Declaration Proposal Text
To: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
cc: common-lisp-object-system@sail.stanford.edu
In-Reply-To: <8704162339.AA22952@hplabsc>
Message-ID: <870417152924.3.MOON@EUPHRATES.SCRC.Symbolics.COM>
This is a good beginning. Not being a fan of machines that require
declarations, I'm going to keep a low profile in this discussion, but
I do have a couple of comments/criticisms for you.
5) If method combination is prohibited for a certain method,
any overhead which is needed to support method combination
in the general case could be avoided.
I agree that this is a non-issue.
(CLASS FOO X)
I think (EXACT-CLASS FOO X) has a lot less potential for confusion.
a user may want to restrict a particular name to be a generic function
I don't see why. I suggest leaving this out unless there is a good
reason for it (which should be articulated).
When a user creates a subclass of a "staticized" class, rather than
changing the semantics in some unclear way, I suggest signalling an
error if there is a conflict between the semantics frozen into the
superclass and the semantics that would exist if the superclass had not
been "staticized". The design principle here is that adding a
"staticize" declaration to a working program shouldn't change what it
does, only how fast it does it.
The name MAKE-STATIC isn't the best. To me, it connotes a function that
returns an object that I can hand to the WRITE-SOUND function and get an
ugly noise from the speaker in my console. FREEZE-CLASS would be better.
∂20-Apr-87 1331 DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET Re: Object creation discussion (at last!)
Received: from RELAY.CS.NET by SAIL.STANFORD.EDU with TCP; 20 Apr 87 13:31:08 PDT
Received: from relay2.cs.net by RELAY.CS.NET id ae19504; 20 Apr 87 16:13 EDT
Received: from ti-csl by RELAY.CS.NET id ax17675; 20 Apr 87 16:05 AST
Received: from Jenner (jenner.ARPA) by tilde id AA16384; Mon, 20 Apr 87 14:48:44 cdt
Message-Id: <2754935345-480598@Jenner>
Date: Mon, 20 Apr 87 14:49:05 CDT
From: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
To: "David A. Moon" <Moon@SCRC-STONY-BROOK.ARPA>
Cc: Common-Lisp-Object-System@SAIL.STANFORD.EDU
Subject: Re: Object creation discussion (at last!)
In-Reply-To: Msg of Fri, 17 Apr 87 14:49 EDT from "David A. Moon" <Moon@scrc-stony-brook.arpa>
Date: Fri, 17 Apr 87 14:49 EDT
From: "David A. Moon" <Moon@scrc-stony-brook.arpa>
Subject: Re: Object creation discussion (at last!)
>> What if multiple initargs that fill the same slot are supplied?
If the same initarg is given more than once in the arguments to make-instance,
the leftmost occurrence prevails, as required by Common Lisp.
If two different initargs that fill the same slot are given in the arguments
to make-instance, the leftmost occurrence prevails (alternatively we could
make this an error, but I think it's simpler to treat it the same as two
occurrences of the same initarg).
A :constructor option whose lambda-list has more than one parameter that
fills a single slot signals an error, whether or not the parameter names
are eq (see proposal below for how it is possible for non-eq parameters
to fill the same slot).
I also added the following related clarification:
When :default-initargs defaults an initarg that
fills a slot, it is treated the same as an :initform slot-option for purposes
of inheritance (note well: the class that specifies the :default-initargs
may not know whether the initarg fills a slot or not, and indeed this may
depend on which subclass of that class we are dealing with). If a single
class specifies more than one default value for a single slot, via
:default-initargs or :initform or both, an error is signalled.
Is this agreeable?
Yes.
Initargs don't have to be keywords, but the entire object creation might not work
very well if any of initargs is not a keyword:
In common Lisp, :allow-other-keys T works only for keyword value pairs. We would
have to slightly change its meaning for make-instance.
In practice this is probably implemented by calling all of the
initialize-instance methods with all of the initargs and automatically adding
&allow-other-keys to the lambda-list in defmethod.
This won't work if there is an initarg which is not a key. The methods that
can be called during object creation (like those on allocate-instance) would be
easier to code if they knew that they would get keyword-value pairs. (if I
understand correctly, those methods would get all the arguments supplied to
make-instance, right?)
I can't understand what you're getting at here. Could you send a follow-up
message this is more explicit?
Take the following example:
(make-instance 'class-1 'SLOT1 2 :AREA 'class-1-area 'JUNK 3
:allow-other-keys t)
SLOT-1 is an initarg for a slot, :AREA is a key for an allocate-instance
method, but JUNK is not a valid initarg. According to your proposal,
:allow-other-keys would tell make-instance to ignore JUNK (ie. return
without signalling an error). In Common Lisp :allow-other-keys T
does not apply to non-keywords like JUNK.
Suppose I have a method like:
(defmethod allocate-instance ((class 'class-1) &key :area
&allow-other-keys)
.....)
If we call allocate-instance with all the initarg-value pairs coming
from the make-instance call and if all the initargs are keywords, then
according to Common Lisp, only the :area keyword is not ignored and we
get the intended effect.
Now, if one of the initargs is not a keyword, then Common Lisp says it
is an error...
My point is, the implementations will have to filter out non keyword
initargs that are not relevant to allocate-instance before calling
allocate-instance if they want strict compliance with CLtL. Is this
true or did I miss something?
>> Can step 2 return an existing object instead of allocating storage,
aborting the remaining steps?
Step 2 can return anything it wants, but the remaining steps are still
executed. To do "interning" you must build a higher-level interface around
make-instance; make-instance always makes. No way is provided for the
metaclass to be able to completely bypass the entire action of MAKE-INSTANCE.
Is this agreeable?
Yes.
∂20-Apr-87 1355 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Object creation discussion (at last!)
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 20 Apr 87 13:55:34 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 120069; Mon 20-Apr-87 16:55:30 EDT
Date: Mon, 20 Apr 87 16:55 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: Object creation discussion (at last!)
To: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
cc: Common-Lisp-Object-System@SAIL.STANFORD.EDU
In-Reply-To: <2754935345-480598@Jenner>
Message-ID: <870420165517.4.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Mon, 20 Apr 87 14:49:05 CDT
From: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
Date: Fri, 17 Apr 87 14:49 EDT
From: "David A. Moon" <Moon@scrc-stony-brook.arpa>
I can't understand what you're getting at here.
In Common Lisp :allow-other-keys T
does not apply to non-keywords like JUNK.
I can't find any evidence for this except at the top of p.62 in CLtL where
it says "It is an error for the first object of each pair to be anything
but a keyword." I was under the impression that it had been decided a
couple of years ago that the last word in this sentence should have been
"symbol", but perhaps that's not true. Unfortunately I lost my copy, but
I think this was in the proposed corrections and clarifications Guy Steele
distributed in December 1985.
If only symbols in the keyword package are allowed as keyword argument
names, my object creation proposal falls apart, as does every other one
that has ever been mailed to this list! I tell you what I'll do; I'll
go find out the format for submissions to the cleanup subcommittee and
send this in. Let's proceed on the assumption that it will be accepted.
∂20-Apr-87 1449 DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET Re: Object creation discussion (at last!)
Received: from RELAY.CS.NET by SAIL.STANFORD.EDU with TCP; 20 Apr 87 14:48:49 PDT
Received: from relay2.cs.net by RELAY.CS.NET id ad20964; 20 Apr 87 17:45 EDT
Received: from ti-csl by RELAY.CS.NET id ap18098; 20 Apr 87 17:37 AST
Received: from Jenner (jenner.ARPA) by tilde id AA19015; Mon, 20 Apr 87 16:10:24 cdt
Message-Id: <2754940257-775701@Jenner>
Date: Mon, 20 Apr 87 16:10:57 CDT
From: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
To: "David A. Moon" <Moon@SCRC-STONY-BROOK.ARPA>
Cc: Common-Lisp-Object-System@SAIL.STANFORD.EDU
Subject: Re: Object creation discussion (at last!)
David,
Another small point:
I did a census of :before and :after :init methods on our system:
There are 864 flavors,
192 :before :init methods,
336 :after :init methods.
The :after :init methods seem to be more common than :before :init.
Did you come up with a different count?
Patrick.
∂21-Apr-87 0812 DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET Re: Object creation discussion (at last!)
Received: from RELAY.CS.NET by SAIL.STANFORD.EDU with TCP; 21 Apr 87 08:12:20 PDT
Received: from relay2.cs.net by RELAY.CS.NET id ab05835; 21 Apr 87 11:06 EDT
Received: from ti-csl by RELAY.CS.NET id ab23071; 21 Apr 87 11:00 AST
Received: from Jenner (jenner.ARPA) by tilde id AA02583; Tue, 21 Apr 87 07:44:11 cdt
Message-Id: <2754996278-4141536@Jenner>
Date: Tue, 21 Apr 87 07:44:38 CDT
From: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
To: "David A. Moon" <Moon@SCRC-STONY-BROOK.ARPA>
Cc: Common-Lisp-Object-System@SAIL.STANFORD.EDU
Subject: Re: Object creation discussion (at last!)
In-Reply-To: Msg of Mon, 20 Apr 87 16:55 EDT from "David A. Moon" <Moon@scrc-stony-brook.arpa>
Date: Mon, 20 Apr 87 16:55 EDT
From: "David A. Moon" <Moon@scrc-stony-brook.arpa>
Subject: Re: Object creation discussion (at last!)
Date: Mon, 20 Apr 87 14:49:05 CDT
From: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
Date: Fri, 17 Apr 87 14:49 EDT
From: "David A. Moon" <Moon@scrc-stony-brook.arpa>
I can't understand what you're getting at here.
In Common Lisp :allow-other-keys T
does not apply to non-keywords like JUNK.
I can't find any evidence for this except at the top of p.62 in CLtL where
it says "It is an error for the first object of each pair to be anything
but a keyword." I was under the impression that it had been decided a
couple of years ago that the last word in this sentence should have been
"symbol", but perhaps that's not true. Unfortunately I lost my copy, but
I think this was in the proposed corrections and clarifications Guy Steele
distributed in December 1985.
I didn't find any reference to this in the clarifications/corrections.
I tell you what I'll do; I'll go find out the format for
submissions to the cleanup subcommittee and send this in. Let's
proceed on the assumption that it will be accepted.
Sounds good.
∂21-Apr-87 1049 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Object creation discussion (at last!)
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 21 Apr 87 10:49:03 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 120677; Tue 21-Apr-87 13:40:33 EDT
Date: Tue, 21 Apr 87 13:40 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: Object creation discussion (at last!)
To: Common-Lisp-Object-System@SAIL.STANFORD.EDU
In-Reply-To: <2754940257-775701@Jenner>
Message-ID: <870421134012.6.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Mon, 20 Apr 87 16:10:57 CDT
From: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
I did a census of :before and :after :init methods on our system:
There are 864 flavors,
192 :before :init methods,
336 :after :init methods.
The :after :init methods seem to be more common than :before :init.
Did you come up with a different count?
When I make these counts I try to exclude the window system, because I
don't consider its design representative of how things would be programmed
today. Unless you've redesigned the MIT window system a lot more than we
have, that's probably true of your system as well.
Here are the make-instance methods I found (in my CLOS object creation
proposal these would be initialize-instance methods, and I have translated
the method qualifiers to the terminology of that proposal):
224 methods total
138 unqualified methods
81 :after methods
5 :around methods
I expected the fraction of :after methods to be lower than 36%. I suppose
it would be good to study them and see why so many are being used, but that
would take more time than I wish to spend today. Maybe later.
For completeness, here are the :init counts, but they are mostly window
flavors:
293 methods total
92 :before methods
23 unqualified methods
170 :after methods
8 :around methods
There is the same preponderance of :after methods, but because :init uses
:daemon method combination (thus almost anything that uses an unqualified
method is, in fact, broken) and because of the influence of the window
system, I don't think there is much to be learned from these numbers.
∂22-Apr-87 1348 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 22 Apr 87 13:48:21 PDT
Received: from Semillon.ms by ArpaGateway.ms ; 22 APR 87 13:44:58 PDT
Date: Wed, 22 Apr 87 13:42 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Object creation discussion (at last!)
To: Moon@STONY-BROOK.SCRC.Symbolics.COM
cc: Common-Lisp-Object-System@Sail.Stanford.edu
Message-ID: <870422134241.3.GREGOR@AVALON.isl.parc.xerox.com>
Line-fold: no
I have a lot of comments and questions about this proposal. I
originally tried to work them in with the running text, but that proved
too cumbersome given the general nature of my comments. What's more,
this message itself isn't all that polished. I thought it would be
better to send it out now so that you would have an idea of what I was
thinking.
My overall comment is that this proposal is a lot more complicated than
either of my previous proposals, in fact it doesn't seem to stress
simplicity at all.
Parts of this proposal provide important, useful and understandable
functionality, which I would like to see in CLOS. Other parts add
considerable conceptual complexity and don't seem to add significant
functional gain. The best example of this is the special method
combination type for initialize-instance.
After I send out this message I will begin working on another message
which lays out the framework of a proposal which incorporates all the
things I really like about your proposal. I think that will be the best
way to make it clear what I have in mind.
My major objections are with:
*** special method combination for the initialize-instance
The special method combination type for initialize instance adds
considerable conceptual overhead for very little functional gain.
I admit that the basic method combination rule is simple enough to
understand. But there are other aspects of this method combination
types which will cause people to ask themeselves questions they will
have a hard time answering with any kind of simple model of this thing.
- if I don't have to say &allow-other-keys here, why do I have to
say it in the normal kind of method combination?
- why is it that I can't count on the methods getting all the initargs
if I use &rest in the lambda-list? Note that this also robs useful
functionality which exists everywhere else in Common Lisp. Specifically,
it makes the &rest args &allow-other-keys idiom not work. This idiom
is very useful for methods which want to process all the initargs in
the init-plist in ways that makes those initargs interact.
- If I redefine a initialize-instance method, will that effect the
interpretation of all the :constructor lambda-lists involved? Will
all those :constructors get fixed?
*** the complex rules for interpreting the lambda-list of :constructors
These rules are just plain complicated. In order to figure out what to
do, you need to know:
The names of all the slots, inherited and local (simple enough).
All the mappings to initargs of those slot names. Inheriting
this information is simple enough, but name mapping is confusing
in general.
All the :default-initargs inherited and local. Once again,
understanding the inheritance here is simple enough.
But putting all this together is pretty complicated. Because it isn't
really three simple inheritance structures that are then combined. I
don't think? I think your rules may cover the following case, but I
don't believe its that simple to reason about.
(defclass foo ()
()
(:default-initargs :bazola ()))
(defclass bar (foo)
((b :initarg :bazola)))
(defclass baz ()
()
(:constructor make-baz (&key bazola)))
(defmethod initialize-instance ((a-baz baz) &key bazola)
(setf (slot-value a-baz 'b) (list bazola (slot-value a-baz 'b))))
*** the overemphasis on getting speed out of the :constructors.
This proposal seems to be mostly focused on getting speed out of using
the :constructors. While I agree that instance creation speed is
important, I am not sure that I like putting so much emphasis on doing
it using :constructors.
For one thing, from the user's point of view, I don't believe it is easy
to understand why constructors should be so much faster. I don't
believe that the reasons why the :constructors are so much faster are
obvious.
For another thing, the ability to be able to compile the :constructors
into something fast leaks all over. The rule that says that particular
initialize-instance methods can't count on getting the entire set of
initargs is an excellent example of this "leakage".
Other specific questions:
- what arguments does allocate-instance get? at one point you say:
From Moon:
2. Initargs that control storage allocation are defined by defining an
allocate-instance method that accepts the initarg as an &key argument.
For example, in systems with areas :area is an initarg for step 2.
The standard does not require any initargs to exist for step 2.
but how does this work? why don't all the allocate instance methods
also have to say &allow-other-keys.
Things that I like and agree with:
Since I have been focusing on things I don't like, it may not be clear
what I do like. Let me try to make explicit some of the major points I
like and agree with.
I like the functionality provided by the :default-initargs option. The
next proposal I will submit has this feature in a slighltly more
CommonLispy syntax.
I agree that the initargs to make instance are "more abstract" than slots.
I agree that constructors should call initialization methods.
I agree that it is important for instance creation to be fast. I agree
that :constructors are the best known way of doing this.
I agree that there should be no defclass option which specifies an
initarg for all the slots.
I probably agree with other, more subtle things that I don't remember
right now.
-------
∂22-Apr-87 1448 Gregor.pa@Xerox.COM CL types --> classes
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 22 Apr 87 14:48:35 PDT
Received: from Semillon.ms by ArpaGateway.ms ; 22 APR 87 14:48:02 PDT
Date: Wed, 22 Apr 87 14:46 PDT
From: Gregor.pa@Xerox.COM
Subject: CL types --> classes
To: Common-Lisp-Object-System@Sail.Stanford.edu
Message-ID: <870422144631.4.GREGOR@AVALON.isl.parc.xerox.com>
Line-fold: no
This message is a brief summary of what I believe we decided about which
Common Lisp types could be classes. This is take from Sonya's very
careful notes and my less careful memory. If we pass this message back
and forth for a while it could probably become a draft of a section in
the design rationale document.
I plan to send something like this (hopefully after it is improved by
the other people on this list) to the CommonLoops list to explain the
changes I am making in built-in classes in the next release of PCL.
Take table 4-1 from CLtL (page 43). From that table, the following
types do NOT have corresponding classes:
ATOM
This is a negation type.
STANDARD-CHAR STRING-CHAR BIT FIXNUM BIGNUM
We decided not to do subranges.
COMMON STREAM FUNCTION
Specification in CLtL too vague. It would be nice if X3J13 fixed stream
and function though.
KEYWORD
Class can change by setf of symbol-package.
SIMPLE-ARRAY SIMPLE-BIT-VECTOR SIMPLE-STRING SIMPLE-VECTOR
?? What is the reason for this ??
PACKAGE READTABLE RANDOM-STATE HASH-TABLE PATHNAME
CLtL only requires that these types be disjoint with each other. We
would like X3J13 to fix these too.
SHORT-FLOAT LONG-FLOAT SINGLE-FLOAT DOUBLE-FLOAT
I don't believe we excluded these but I believe either Pavel or Patrick
said they would write up the rules about how these work.
-------
∂22-Apr-87 1533 Pavel.pa@Xerox.COM Re: CL types --> classes
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 22 Apr 87 15:33:09 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 22 APR 87 15:19:17 PDT
Date: 22 Apr 87 15:19 PDT
From: Pavel.pa@Xerox.COM
Subject: Re: CL types --> classes
In-reply-to: Gregor.pa's message of Wed, 22 Apr 87 14:46 PDT
To: Common-Lisp-Object-System@Sail.Stanford.edu
Message-ID: <870422-151917-4178@Xerox>
SHORT-FLOAT LONG-FLOAT SINGLE-FLOAT DOUBLE-FLOAT
I don't believe we excluded these but I believe either Pavel or
Patrick said they would write up the rules about how these work.
I indeed said that I would write these up. I'll be able to get to it later this week.
Pavel
∂22-Apr-87 1637 Gregor.pa@Xerox.COM note about clos instance disjointness
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 22 Apr 87 16:37:24 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 22 APR 87 16:37:59 PDT
Date: 22 Apr 87 16:37 PDT
From: Gregor.pa@Xerox.COM
Subject: note about clos instance disjointness
To: Common-Lisp-Object-System@Sail.Stanford.edu
Message-ID: <870422-163759-4304@Xerox>
I don't know exactly where this would fit in in the document, but we
need to say that instances of standard-classes have type disjoint with
all other types. This is kind of obvious of course, but should be made
explicit.
∂22-Apr-87 1639 Gregor.pa@Xerox.COM funcallable-standard-class
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 22 Apr 87 16:39:50 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 22 APR 87 16:40:52 PDT
Date: 22 Apr 87 16:40 PDT
From: Gregor.pa@Xerox.COM
Subject: funcallable-standard-class
To: Common-Lisp-Object-System@Sail.Stanford.edu
Message-ID: <870422-164052-4316@Xerox>
Another note just to record something we all need to think about.
We need to document the metaclass which generic-function classes use.
This is so that people can define their own generic-function classes
(the need to know what :metaclass to specify).
Also, the funcallable-instance functionality is useful enough, and easy
enough to document that I think we should make it generally available.
This note will serve to remind me to mail out a proposal about this
based on what is now in PCL.
∂22-Apr-87 1729 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 22 Apr 87 17:29:01 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 22 APR 87 17:30:04 PDT
Date: Wed, 22 Apr 87 17:28 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Object creation discussion (at last!)
To: Moon@STONY-BROOK.SCRC.Symbolics.COM
cc: Common-Lisp-Object-System@Sail.Stanford.edu
Message-ID: <870422172838.5.GREGOR@AVALON.isl.parc.xerox.com>
Line-fold: no
OK, here is a try at a counter proposal which tries to show what I do
and don't like about your proposal. This isn't finished yet, once again
I thought it would be better to send it out now so that you could see
where I was headed.
Basically, my proposal keeps these features from your proposal:
:initarg slot option
:default-initargs defclass option (different syntax)
make-instance processes slot initargs or evaluates initforms
constructors can be faster because they can inline stuff
and gets rid of these:
the new method combination type for initialize instance
using &key in an initialize-instance method augments legal initargs
SO:
The :initarg slot option can be used to teach make-instance the name of
an initarg which can be used to initialize the value of this slot from
the initargs passed to make-instance. The way to think of this option
is that it implements the abstract initarg name to slot name mapping for
make-instance. For convenience, specifying an :initarg name in a slot
description also includes that initarg name in the :default-initargs of
the defclass.
The default-initargs defclass option serves two purposes. It specifies
all the initargs which can be passed to make-instance of this class, and
it specifies default values for some of those initargs. The syntax of
this option is a lot like the part of a lambda-list following &key
(which serves two similar purposes). For example:
(:default-initargs :foo :bar (:baz 3))
says that this class accepts initargs :FOO, :BAR and :BAZ. Furthermore,
the default value of the :BAZ initarg is 3. The default values of :FOO
and :BAR are both nil.
So, a defclass form like this:
(defclass position ()
((x :initarg :x)
(y :initarg :y))
(:default-initargs (:x 0) (:y 0) :rho :theta))
can be read as saying: make-instance with a first argument of POSITION
accepts 4 initargs (:x :y :rho :theta). The default value for :x and :y
is 0; the default value for :rho and :theta is nil. When make-instance
is called, it sets the value of the x slot of the instance to the value
of the :x initarg ..(same for y and :y).
make-instance calls allocate-instance generic-function with all the
initargs (the ones passed to make-instance plus any defaulted ones). It
then sets the values of any slots for which initargs appear in the
initargs, it then sets the values of the remaining slots from their
initforms. It then calls the intialize-instance generic-function with
all the initargs.
constructors can be thought of as providing a "boa" syntax for specific
calls to make-instance. Because make-instance is a function and not a
generic-function, constructors are allowed to "perform the same actions
calling make-instance would have" rather than calling make-instance
directly. As a result, in many implementations, constructors are faster
than the corresponding call to make-instance. To produce the "call to
make-instance" a constructor interprets its lambda-list as follows:
- if an element of its lambda-list names an initarg acceptable to
this class, then that initarg pair will appear in the "call to
make-instance".
- if an element of the lambda list does not name an initarg, but
names a slot this is an abbreviation for defining a gensymed initarg
for that slot and using that gensym.
[This needs work or perhaps need to be removed. I want to try
to make this case be an abbreviation for something that is
already understood.]
- if neither of the above are true, calling the constructor signals
an error. Some implementations may warn earlier of course.
initialize-instance uses the default kind of method combination. Note
that all initialize-instance methods should say &allow-other-keys.
Under some programming styles, many initialize-instance methods will be
:before methods. Under other programming styles they will not be, they
will probably use call-next-method.
-------
∂23-Apr-87 0953 kempf%hplabsc@hplabs.HP.COM Re: CLOS Type Cleanup
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 23 Apr 87 09:51:39 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 23 Apr 87 08:13:56 pst
Received: by hplabsc ; Thu, 23 Apr 87 08:14:08 pst
Date: Thu, 23 Apr 87 08:14:08 pst
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8704231614.AA11598@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: Re: CLOS Type Cleanup
Gregor's list looks accurate.
One comment on FUNCTION. If X3J13 fixes this, then a nice solution
about what to do with funcallable instances might be to make them
a subclass of FUNCTION.
jak
∂23-Apr-87 1225 kempf%hplabsc@hplabs.HP.COM Re: (long) CLOS Declaration Proposal Text
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 23 Apr 87 12:25:23 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 23 Apr 87 09:10:55 pst
Received: by hplabsc ; Thu, 23 Apr 87 09:09:09 pst
Date: Thu, 23 Apr 87 09:09:09 pst
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8704231709.AA12554@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: Re: (long) CLOS Declaration Proposal Text
Some additional comments on the declaration discussion,
and Moon's reply. Dick Gabrial, are you still there?
> 5) If method combination is prohibited for a certain method,
> any overhead which is needed to support method combination
> in the general case could be avoided.
>
>I agree that this is a non-issue.
OK, then, unless anyone else objects, we can drop any consideration
of declarations for method combination.
> (CLASS FOO X)
>
>I think (EXACT-CLASS FOO X) has a lot less potential for confusion.
This syntax is fine with me.
> a user may want to restrict a particular name to be a generic function
>
>I don't see why. I suggest leaving this out unless there is a good
>reason for it (which should be articulated).
I would like to see this resolved in the context of the GFLET,
GFLABELS, and GLAMBDA proposals discussed earlier. In particular,
I would like the ability to say:
(MAPCAR <some local generic function> LIST-OF-OBJECTS)
and not have to do a global definition of the methods. A GENERIC-FUNCTION
declaration might allow us to get away without introducing GFLET
and GFLABELS. For example, the following could be legal:
(DEFUN EXAMPLE (OBJECT-LIST)
(FLET
(FOO ((A FOO-CLASS)) A)
(FOO ((B BAZ-CLASS)) B)
)
(DECLARE (GENERIC-FUNCTION FOO))
(MAPCAR #'FOO OBJECT-LIST)
)
or some similar syntax. Notice that this will not resolve the problem
of GLAMBDA, however.
>When a user creates a subclass of a "staticized" class, rather than
>changing the semantics in some unclear way, I suggest signalling an
>error if there is a conflict between the semantics frozen into the
>superclass and the semantics that would exist if the superclass had not
>been "staticized". The design principle here is that adding a
>"staticize" declaration to a working program shouldn't change what it
>does, only how fast it does it.
I agree here.
>The name MAKE-STATIC isn't the best. To me, it connotes a function that
>returns an object that I can hand to the WRITE-SOUND function and get an
>ugly noise from the speaker in my console. FREEZE-CLASS would be better.
I like the idea of using FREEZE-<something> for optimization and other
postdevelopment processing. I would suggest the following additions to
the metaobject protocol for this purpose:
FREEZE-REDEFINITION <class>
Takes a class object as an argument and causes the definition of the
class to be frozen. Any attempt to redefine the class will cause an
error to be signalled. In order for a class's definition to be frozen,
all superclass definitions must be frozen as well. An error will be
signalled if this is not the case.
FREEZE-SLOT-LAYOUT <class>
Causes slots to be located at fixed offsets if the class is used as
a superclass during inheritence. Signals an error if all superclasses
do not have frozen slot layout as well.
FREEZE-CLASS-PRECEDENCE-LIST <class>
The class precedence list for the class argument is calculated (if
it hasn't already been) and the class precedence for subclasses
is frozen. An attempt to define a subclass whose included direct
supers would cause a difference class precedence ordering causes
an error to be signalled. An error is signalled if all superclasses
of the class argument do not have frozen class precedence lists
as well.
jak
∂23-Apr-87 1249 kempf%hplabsc@hplabs.HP.COM Re: Object Creation Discussion (at last!)
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 23 Apr 87 12:48:38 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 23 Apr 87 08:02:47 pst
Received: by hplabsc ; Thu, 23 Apr 87 08:03:20 pst
Date: Thu, 23 Apr 87 08:03:20 pst
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8704231603.AA11434@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: Re: Object Creation Discussion (at last!)
Comments on Moon's creation note (and subsequent discussion):
OVERALL COMMENTS:
I agree with Gregor that the proposal needs simplification. The
special method combination type, the overemphasis on constructor
speed (they could be simply declared IN-LINE) and the complex
rules for lambda-list interpretation need some reworking.
In addition, I would like to see the syntax for the :INITFORM, :INITARG,
and :DEFAULT-INITARG options better integrated (see below for addition to
Gregor's suggestion).
SPECIFICS:
*On symbols as initarg keys:
> "initargs" (initialization arguments) are a set of named arguments that
> control object creation and initialization. Each initarg has a name, which
> is a symbol (not necessarily a keyword), and a value. The arguments to
> make-instance, excepting the first, taken in pairs, are initargs.
Subsequent discussion has cleared up this point as a potential area
of incompatibility which needs a cleanup committee proposal.
*On storage allocation:
> Also customizable by the metaclass, because the metaclass controls the
> stored representation of instances.
This should probably be the "recommended" way of doing things.
Though it's probably not a good idea to prohibit it, I think it
should be encouraged for portability reasons. The metaobject protocol
should be the lowest level, portable interface into the object system.
Anything below should be system dependent.
*On the proposed additional slot and class definition options:
>3. Customizable by slot-description, which specifies a default value for the
> slot and whether the slot can be filled with a value specified by the
> client; if so, the slot-description specifies the name of the initarg
> whose value is stored into the slot.
>The :default-initargs defclass option is followed by alternating initarg
>names and forms. If an initarg is not specified by the client nor by
>a :default-initargs option in a more specific class, the form is evaluated
>in the lexical environment of the defclass and the resulting value is used
>for the initarg.
From subsequent discussion, it seems as if an additional DEFCLASS
option, :DEFAULT-INITARGS is being proposed. I wonder if this
is needed, considering that a user can already specify an initialization
value via the :INITFORM option? Perhaps the metaclass ought to
attend to this? Or the :INITFORM and :DEFAULT-INITARGS options should
be merged?
In particular:
>So, a defclass form like this:
>
> (defclass position ()
> ((x :initarg :x)
> (y :initarg :y))
> (:default-initargs (:x 0) (:y 0) :rho :theta))
>
Consider what the syntax would be if you wanted to specify an initform
as well:
(defclass position ()
((x :initarg :x :initform 0)
(y :initarg :y :initform 0))
(:default-initargs (:x 0) (:y 0) :rho :theta))
So why not simplify this as:
(defclass position ()
((x :initarg (:x 0))
(y :initarg (:y 0)))
( <some appropriate key> :rho :theta)
)
Semantics are:
1) If MAKE-INSTANCE is called without an initialization list,
the initialization values of X and Y are set to zero.
2) If initialization values are supplied in the initialization list,
then they are used.
3) :RHO and :THETA are valid as keys for initargs to MAKE-INSTANCE in
any case. If no value is given, then they are NIL.
A suggestion for <some appropriate key> would be :ADDITIONAL-INITARGS.
*On MAKE-INSTANCE and modules:
>>> Is make-instance an intra-module or inter-module interface?
>
>Both.
>
>>> Do the arguments to make-instance correspond directly to actual stored
>slots, or are they a more abstract concept, whose implementation in terms
>of slots or in terms of something else is hidden from the caller?
>
>More abstract, because make-instance is often used as an inter-module
I don't understand. What is understood here by the word "module"?
Has it any relation to *MODULES* on pg. 188 and thus to the
PROVIDE/REQUIRE mechanism?
*On constructors:
>>> What is the lambda-list of a constructor created by a :constructor
>option with no lambda-list specified?
>
>It accepts the same arguments as make-instance, excepting the first.
>
>>> Do constructors call initialization methods?
>
>Yes.
>
>>> Why do we have a :constructor option to defclass?
>
>For speed; make-instance is interpretive, while constructors are compiled,
>since they know the exact class that they are constructing, and since they can
>be automatically recompiled if the class or any of its superclasses changes.
I'm not quite sure how this fits in with the metaclass protocol.
What if a user defines a constructor function to make an object out
of a list, or to return a symbol? If the constructor function tries
to call initializaton methods, then what will be the result? Also,
if the initialization succeeds, method definition and lookup might
do the wrong thing if the low level structure of an instance is
not what is expected. As an example, say the constructor function
returns an integer, and there are two methods on a generic function,
one with an INTEGER selector and one with the same class as the
erring constructor function.
In addition, I think the IN-LINE declaration could help getting speed
out of a constructor.
*On the context in which an initialization is run:
>The :initarg slot-option specifies that this slot can be filled in, and
>specifies the initarg name. This slot-option can be given more than once.
>
>There is no defclass option that specifies initargs for all the slots,
>because that would endorse a particular convention for naming initargs.
>
Are the initforms run in the context of INITIALIZE-INSTANCE? Is WITH-SLOTS
acceptable within an initform?
I think this proposal would satisfy Dave Martin's request for initialization
hooks. I'm enclosing his message on this below.
jak
---------------------------------------------------------------------------
Well, what we currently have is the following:
defmethod initialize ((self new-object) init-plist)
(initialize-from-defaults self)
(initialize-from-init-plist self init-plist)
(apply #'new-instance self init-plist))
Where the new-instance function is defined to do nothing for new-object but
takes an arbitrary list of keywords (generally including slot names) to
set the values.
What I would *like* to see is the function initialize (or some other name)
initialize from the defaults, and then initialize from the init-plist only
on slots keywords (this is what we do, I rewrote initialize-from-init-plist
to ignore non-keyword slots) and then call a class specific function to
do the remaining setup. It would be nice if slots which were read-only
were still settable inside the initialization code (e.g. the resource id of
a window object should be read-only, but I can't set it until the new-instance
function is called).
I was thinking about changing the initialize function to do the following:
1) initialize from the default value of each keyword slot; 2) use the setf
function for setting from the init-plist argument for any keywords which
correspond to slots; and 3) call a user-specifiable routine (i.e. have a slot
in the class called initialize-method) which would be mandatory for each class
and would be hacked to allow call-next-method to find the appropriate method
for the super classes even if the method name differed.
With this setup we avoid having to set aside new-instance as a reserved
name, allow the system to set slot values appropriately (using the setf method
should be a flaggable option), and hopefully be able to reduce the size
of the new-instance function.
∂23-Apr-87 1456 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: CLOS Declaration Proposal
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 23 Apr 87 14:56:52 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 123315; Thu 23-Apr-87 17:53:57 EDT
Date: Thu, 23 Apr 87 17:53 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: CLOS Declaration Proposal
To: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
cc: common-lisp-object-system@sail.stanford.edu
In-Reply-To: <8704231709.AA12554@hplabsc>
Message-ID: <870423175345.0.MOON@EUPHRATES.SCRC.Symbolics.COM>
The only problem with using functions, rather than defclass options,
to freeze attributes of classes is how to make these functions take
effect at compile time, which is when they have to take effect to be
of any use. Propose something.
∂23-Apr-87 1722 kempf%hplabsc@hplabs.HP.COM Re: CLOS Declaration Proposal
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 23 Apr 87 17:22:03 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 23 Apr 87 15:38:10 pst
Received: by hplabsc ; Thu, 23 Apr 87 15:27:22 pst
Date: Thu, 23 Apr 87 15:27:22 pst
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8704232327.AA18524@hplabsc>
To: Moon@STONY-BROOK.SCRC.Symbolics.COM, kempf%hplabsc@hplabs.HP.COM
Subject: Re: CLOS Declaration Proposal
Cc: common-lisp-object-system@sail.stanford.edu
I understand the problem. I can see two possible solutions.
1) Introduce a declaration which invokes the metaclass functions.
Something like:
(PROCLAIM '(FREEZE-CLASS-PRECEDENCE-LIST FOO))
in the DEFSYS file would cause the class precedence list to be
frozen.
2) Leave it up to use of (EVAL-WHEN (COMPILE EVAL) ... ) to
do it.
I don't like either of these much, but like a defclass option even
less, since there are already so many.
I'll give it some more thought. Thanks for pointing this out.
jak
∂23-Apr-87 2020 Gregor.pa@Xerox.COM Re: Object Creation Discussion (at last!)
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 23 Apr 87 20:20:33 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 23 APR 87 18:24:27 PDT
Date: 23 Apr 87 18:24 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Object Creation Discussion (at last!)
In-reply-to: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>'s message of Thu,
23 Apr 87 08:03:20 pst
To: kempf%hplabsc@hplabs.HP.COM
cc: common-lisp-object-system@sail.stanford.edu
Message-ID: <870423-182427-1534@Xerox>
Date: Thu, 23 Apr 87 08:03:20 pst From: Jim Kempf
<kempf%hplabsc@hplabs.HP.COM>
From subsequent discussion, it seems as if an additional
DEFCLASS option, :DEFAULT-INITARGS is being proposed. I wonder if
this is needed, considering that a user can already specify an
initialization value via the :INITFORM option? Perhaps the
metaclass ought to attend to this? Or the :INITFORM and
:DEFAULT-INITARGS options should be merged?
I don't think we have reduced initialization to its fundamental
components yet. In this message I am trying to attack some of our
assumptions to see if that can help us get at those fundamental
components.
What if we got rid of :initform??
What is the purpose of :initform anymore? You only need it when you
want to specify the default value for a slot that isn't set by any
initarg. This means that we have two mechanisms which do almost the
same thing -- initargs which set slots are almost a superset of
initforms. This is a sure sign of bad modularity.
Let's just pretend you didn't have initforms but that you did want to be
able to have some slots which had "default values" but which weren't
initable from the initargs passed to make-instance.
(in the terminology of all previous proposals:
(defclass position () ((x 0) (y 0)))
now, adopting a slighlty different syntax for :default-initargs, you
could say:
(defclass position ()
(x
y)
(:default-initargs (:moosefish1 0 x)
(:moosefish2 0 y)))
(apologies to Alan Snyder)
This new syntax for default-initargs reads:
":moosefish1 is an initarg whose default value is 0 and which
make-instance
uses to set the value of the x slot..."
:moosefish1 is some name which is chosen to be weird enough that no-one
will ever use it. So, "in-effect" the slots are not initable in the
call to make-instance. When the initialize-instance generic-function is
called (whether that call is open coded or not) the values of the x and
y slots are sure to be 0.
:moosefish1 is silly of course (more apologies to Alan), but what about
something like:
(defclass position ()
(x
y)
(:default-initargs (nil 0 x)
(nil 0 y)))
What I am trying to do is seperate what I perceive as the separate parts
of what is going on into separate places.
1. the structure of the instance is specified, the slots and their
allocation.
2. the legal initarg names are specified
3. the default values for the initargs are specified
4. automatic initialization of the values of some of the slots by
make instance is specified.
the slot descriptions specify 1 (the structure of the instance)
the cars of the :default-initargs option arguments specify the legal
initarg names
the cadrs specify the default value
the caddrs specify which slots are set from the value.
think of the :default-initargs syntax as being something like the syntax
of what follows &key in a lambda list except reversed, so each can be
one of:
initarg | (initarg default-value) | (initarg default-value slot-name)
∂23-Apr-87 2132 Moon@STONY-BROOK.SCRC.Symbolics.COM CL types --> classes
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 23 Apr 87 21:32:39 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 123676; Fri 24-Apr-87 00:32:46 EDT
Date: Fri, 24 Apr 87 00:32 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: CL types --> classes
To: Common-Lisp-Object-System@Sail.Stanford.edu
In-Reply-To: <870422144631.4.GREGOR@AVALON.isl.parc.xerox.com>
Message-ID: <870424003237.6.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Wed, 22 Apr 87 14:46 PDT
From: Gregor.pa@Xerox.COM
My notes generally agree with your message. Here are the differences
and extensions:
They say COMPILED-FUNCTION is in the same boat with FUNCTION.
KEYWORD
Class can change by setf of symbol-package.
There was an argument about whether Common Lisp allows setf of
symbol-package, but I think we came up with a way to use IMPORT to
change something that isn't a keyword into a keyword. Traditionally
the type of an object is something you can't change. Does the
existence of CHANGE-CLASS mean that KEYWORD should be a class?
I feel like leaving out KEYWORD on the basis that extra classes
shouldn't be put in if they aren't clearly useful, but this is an
issue that could go either way.
SIMPLE-ARRAY SIMPLE-BIT-VECTOR SIMPLE-STRING SIMPLE-VECTOR
?? What is the reason for this ??
Subrange is scrawled next to these on my notes. If these are
subranges then KEYWORD is too.
PACKAGE READTABLE RANDOM-STATE HASH-TABLE PATHNAME
CLtL only requires that these types be disjoint with each other. We
would like X3J13 to fix these too.
There are probably a lot of implementations in which one or more of these
is a subtype of ARRAY. That might be hard to fix efficiently?
No list type-specifier names a class and no deftype names a class, say
my notes.
SHORT-FLOAT LONG-FLOAT SINGLE-FLOAT DOUBLE-FLOAT
I don't believe we excluded these but I believe Pavel
said he would write up the rules about how these work.
The issue was that if there are methods defined for both
SHORT-FLOAT and SINGLE-FLOAT, but these types are collapsed into
one, the precedence order of the methods is not well-defined.
The only thing we thought of in the meeting was to signal an error
when this happens, but I suspect that would be unsatisfactory in
practice.
In the precedence relationships for built in classes with
multiple direct superclasses, I think we decided on
(defclass null (list symbol) ...)
(defclass vector (array sequence) ...)
(defclass list (cons sequence) ...)
Are we ready to write this up yet?
∂26-Apr-87 2231 Moon@STONY-BROOK.SCRC.Symbolics.COM Object creation discussion (at last!)
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 26 Apr 87 22:30:57 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 124868; Mon 27-Apr-87 01:31:17 EDT
Date: Mon, 27 Apr 87 01:30 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Object creation discussion (at last!)
To: Common-Lisp-Object-System@sail.stanford.edu
In-Reply-To: <870416002258.1.MOON@EUPHRATES.SCRC.Symbolics.COM>,
<870421134012.6.MOON@EUPHRATES.SCRC.Symbolics.COM>,
<870422134241.3.GREGOR@AVALON.isl.parc.xerox.com>,
<870422172838.5.GREGOR@AVALON.isl.parc.xerox.com>,
<8704231603.AA11434@hplabsc>,
<870423-182427-1534@Xerox>
Message-ID: <870427013057.6.MOON@EUPHRATES.SCRC.Symbolics.COM>
I can see from the misunderstanding in the mail that I did an abysmal job
of communicating my ideas. I'll try to send a more comprehensible essay
tomorrow, but for now I would like to just clarify a couple of points and
then make some comments on excerpts from the mail in places where they
might help communication.
Complexity and simplicity are partly matters of taste, and largely matters
of point of view. I try to take the point of view of the majority of
programmers, who are using the outer interfaces of the system without
necessarily understanding everything that's going on inside. No matter how
beautifully we explain it, most programmers simply won't read beyond the
point where they think they know everything they need to know to get their
immediate job done. Now, it may be that we will decide that we would
rather make life more complicated for people writing initialization methods
in order to make the conceptual explanation shorter. That would be okay
with me if it's done for good reasons, but we shouldn't just dismiss the
other way without understanding it and understanding why I proposed it. I
have a feeling this message isn't going to explain it adequately either,
and if that happens I will apologize and follow up with a more carefully
written explanation.
One key point that I was trying to convey, and I think partially succeeded,
was the need for information hiding (abstraction) in the arguments to
make-instance and in relations among the various initialization
specifications attached to a class and its superclasses.
Another key point, which I don't think came through, was that each initarg
should be explicitly defined, and should be defined in exactly one place.
This is simply good modularity.
Some aspects of what I proposed were reacting to user complaints about the
way Flavors does it. I have the ambition of making this new standard
better than Flavors.
All this leads to the idea that initargs of types 2 and 4 (in the
nomenclature of my 16 Apr message) should be defined by methods, since
their meaning is implemented by methods. Similarly, type 3 should be
defined by slot-options, since their meaning is entirely involved with
slots. In Flavors, type 4 have the ugly property that they have to be
defined in two places, once in the method that implements them and again in
a defflavor form; it's easy to get these two places out of sync. Hence the
proposal to use the lambda-list of a defmethod as the way to define these
initargs. Along with this, I tried to eliminate clunky syntax from
initialization methods, hence the elimination of &allow-other-keys and the
elimination of having to write :before all the time. If this is too
confusing, we could invent a new syntax that both defines initargs and
defines the method that implements them. Clearly this is the weakest part
of my proposal.
We could obviously simplify things a lot by getting rid of the :constructor
option to defclass. I didn't put it in, at least not this year. I do think
it ought to remain, in spite of its inherent complexity in any initialization
proposal (previous ones I've seen have glossed over this rather than solving
it), because I believe many users will find it quite useful.
Date: Wed, 22 Apr 87 13:42 PDT
From: Gregor.pa@Xerox.COM
The special method combination type for initialize instance adds
considerable conceptual overhead for very little functional gain.
The goal was not functional gain, that is, the ability to program something
you couldn't program before, but rather syntactic simplicity. Perhaps in
the end we'll decide it's not worth it, but I'd like us to keep considering
the question a bit longer.
I admit that the basic method combination rule is simple enough to
understand. But there are other aspects of this method combination
types which will cause people to ask themeselves questions they will
have a hard time answering with any kind of simple model of this thing.
- if I don't have to say &allow-other-keys here, why do I have to
say it in the normal kind of method combination?
True, this is a problem.
- why is it that I can't count on the methods getting all the initargs
if I use &rest in the lambda-list? Note that this also robs useful
functionality which exists everywhere else in Common Lisp. Specifically,
it makes the &rest args &allow-other-keys idiom not work. This idiom
is very useful for methods which want to process all the initargs in
the init-plist in ways that makes those initargs interact.
I can't figure out precisely all you're saying here, but I think this just
stems from a half-baked idea that I wouldn't have included in the proposal
if I had spent more time thinking about it before sending it. I was trying
to do an efficiency optimization involving not consing lists of slot-filling
initargs that have been defaulted, and I now think that was premature. We
can revisit the question after the major framework is agreed upon, plus I
always (except when I fall from grace) believe in the principle that designs
should first consider what is right, and optimizations should be subordinate
to that, fitting into an existing framework rather than distorting it.
- If I redefine a initialize-instance method, will that effect the
interpretation of all the :constructor lambda-lists involved? Will
all those :constructors get fixed?
Of course the constructors have to get fixed if you change something in a
way that changes the compiled code that was supposed to have been generated
for them. I think that fact is independent of details of all object
creation proposals. The specific example that I think you were thinking
about is when a positional parameter of a constructor is changed from
something that only fills a slot and isn't cared about by initialize
methods, to something that both fills a slot and is seen by initialize
methods. In my proposal, adding an initialize-instance method could do
this. In your most recent one, evaluating a defclass could do this.
*** the complex rules for interpreting the lambda-list of :constructors
.... example elided ....
I don't see any problem here that I added. The lambda-list syntax of
constructors is like defstruct, not like defun, but that's already in
87-002.
Your example also touches upon the lambda-list of initialize-instance
methods. Here the default for an argument that is already defaulted by
defclass options would never be used, because all calls that reached the
initialize-instance method would necessarily have to supply that argument.
But I don't think there's anything new to Common Lisp in that.
- what arguments does allocate-instance get?
allocate-instance was intended to work exactly like initialize-instance,
however the latter turns out.
Date: Wed, 22 Apr 87 17:28 PDT
From: Gregor.pa@Xerox.COM
The default-initargs defclass option serves two purposes. It specifies
all the initargs which can be passed to make-instance of this class, and
it specifies default values for some of those initargs.
This is an important modularity mistake, in my opinion. By combining these
two things, which ought to be separate, you have lost the ability for one
class to specify a default value for an initarg defined by another class.
If specifying a default value always defines an initarg, there is no way to
check the consistency of the set of initargs with default values specified
against the set of initargs actually defined. If there is a misspelling,
the default value will simply be discarded, since no method will receive it
and do something with it.
constructors can be thought of as providing a "boa" syntax for specific
calls to make-instance.
This can't work as long as constructors are allowed to fill slots that
make-instance is not allowed to fill, which I think is an important ability
because it gives the programmer more control over interfaces.
Date: Thu, 23 Apr 87 08:03:20 pst
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
From subsequent discussion, it seems as if an additional DEFCLASS
option, :DEFAULT-INITARGS is being proposed. I wonder if this
is needed, considering that a user can already specify an initialization
value via the :INITFORM option? Perhaps the metaclass ought to
attend to this? Or the :INITFORM and :DEFAULT-INITARGS options should
be merged?
This indicates that I completely failed to convey what :default-initargs is
about, and that in turn may possibly indicate that :default-initargs should
be flushed. In my proposal there are two ways to specify a default for an
initarg: at the point of definition, and remotely. To explain: when
defining an initarg one can specify right there, locally, a default value
form. For initargs that fill slots, this is the existing :initform
slot-option; no need to invent anything new there. For initargs that are
implemented by methods, this is the existing defaulting mechanism in the
lambda-list; again, no need to invent anything new. Now for remote
defaulting: here the idea is that one class defines what an initarg means,
while a second class specifies a default for it; this is :default-initargs.
When you mix the two classes together, the default meets up with the
implementation and things work. The reason remote defaulting is desirable
is twofold: (1) it's often useful when mixing classes together for one
class to customize another class by specifying initialization options, in
addition to the existing ability to customize a class by shadowing or
wrapping methods; (2) for modularity reasons, when class A customizes class
B by specifying an initarg that class B defines, class A shouldn't have to
know whether the initarg fills a slot or is implemented by a method. If
not for reason (2), remote defaulting wouldn't require a new mechanism,
because it could be implemented using the existing mechanism of :initform
for slot initargs plus call-next-method-with-arguments (proposed but not
yet accepted) for method initargs. But I think reason (2) is important.
I don't understand. What is understood here by the word "module"?
Has it any relation to *MODULES* on pg. 188 and thus to the
PROVIDE/REQUIRE mechanism?
No relation. I meant the general computer-science concept of modules as
subdivisions of a program that have some independence from each other, not
something realized as an object in an implementation.
What if a user defines a constructor function to make an object out
of a list, or to return a symbol? If the constructor function tries
to call initializaton methods, then what will be the result? Also,
if the initialization succeeds, method definition and lookup might
do the wrong thing if the low level structure of an instance is
not what is expected. As an example, say the constructor function
returns an integer, and there are two methods on a generic function,
one with an INTEGER selector and one with the same class as the
erring constructor function.
In addition, I think the IN-LINE declaration could help getting speed
out of a constructor.
By "constructor", I meant the functions defined by the :constructor option
to defclass. The syntax of that option doesn't admit any of the above
possibilities.
I wonder if you were getting at a different issue: what if the value
returned by the allocate-instance method is not an instance of the exact
class being instantiated? If the caller of allocate-instance simply
assumes the type of this value is correct, all kinds of terrible things
could happen, especially if slot-filling is open-coded in constructors.
Danny's chapter 3 speaks of "recognizable blocks of storage", and I think
we need to say something like that here. I think this issue is largely
independent of the other details of object creation proposals, and needs to
be resolved on its own. It's hard for me to say much about it since I don't
understand why anyone would need to customize allocate-instance.
Are the initforms run in the context of INITIALIZE-INSTANCE?
We agreed some time ago that they are in the lexical environment in which
the defclass was evaluated.
Is WITH-SLOTS acceptable within an initform?
WITH-SLOTS works everywhere (although it works more efficiently in some
places). However, the object being created is not lexically available in
the environment of initforms, so it isn't possible to access its slots.
Some people have proposed that the object and the initargs be lexically
available to initforms, and this does open some intriguing expressive
possibilities. However, I think I prefer to say that anything this
complicated should be done in initialize-instance methods instead.
Date: 23 Apr 87 18:24 PDT
From: Gregor.pa@Xerox.COM
What is the purpose of :initform anymore? You only need it when you
want to specify the default value for a slot that isn't set by any
initarg. This means that we have two mechanisms which do almost the
same thing -- initargs which set slots are almost a superset of
initforms. This is a sure sign of bad modularity.
On the contrary, I think it's a sign of good modularity! The two
mechanisms do almost the same thing inside the implementation, but from the
point of view of someone on the outside who doesn't know the information
that is supposed to be hidden from him by modular abstraction, they do
rather different things. I could give a longer explanation of what I mean,
but it's late, this message is already too long to ask anyone to read
carefully, and I think I would just be repeating what I said a bit earlier.
(defclass position ()
(x
y)
(:default-initargs (nil 0 x)
(nil 0 y)))
What I am trying to do is seperate what I perceive as the separate parts
of what is going on into separate places.
The reason I don't like this is that the information about a slot is no
longer all in one place. Another way of saying it is that I think that
information in defclass should be organized spatially rather than
temporally, i.e. information pertaining to one slot should be together,
rather than putting information pertaining to one phase of object creation
together. One of the ways that I think defclass is better than defflavor
is that it has done a better job of spatial organization by putting more
of the information about a slot into slot options instead of scattering it
around in various options some of which refer back to the slot by name.
∂27-Apr-87 1329 DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET Re: Object creation discussion (at last!)
Received: from RELAY.CS.NET by SAIL.STANFORD.EDU with TCP; 27 Apr 87 13:29:14 PDT
Received: from relay2.cs.net by RELAY.CS.NET id ab26381; 27 Apr 87 16:20 EDT
Received: from ti-csl by RELAY.CS.NET id ah07490; 27 Apr 87 16:17 EDT
Received: from dsg (juliett.ARPA) by tilde id AA04504; Mon, 27 Apr 87 14:27:09 cdt
Received: From Jenner By dsg Via CHAOS-NET With CHAOS-MAIL; Mon, 27 Apr 87 14:28:46 CDT
Message-Id: <2755538893-1609268@Jenner>
Date: Mon, 27 Apr 87 14:28:13 CDT
From: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
To: Common-Lisp-Object-System@SAIL.STANFORD.EDU
Subject: Re: Object creation discussion (at last!)
In-Reply-To: Msg of Mon, 27 Apr 87 01:30 EDT from "David A. Moon" <Moon@scrc-stony-brook.arpa>
Date: Mon, 27 Apr 87 01:30 EDT
From: "David A. Moon" <Moon@scrc-stony-brook.arpa>
Subject: Object creation discussion (at last!)
I can see from the misunderstanding in the mail that I did an abysmal job
of communicating my ideas. I'll try to send a more comprehensible essay
tomorrow, but for now I would like to just clarify a couple of points and
then make some comments on excerpts from the mail in places where they
might help communication.
Complexity and simplicity are partly matters of taste, and largely matters
of point of view. I try to take the point of view of the majority of
programmers, who are using the outer interfaces of the system without
necessarily understanding everything that's going on inside. No matter how
beautifully we explain it, most programmers simply won't read beyond the
point where they think they know everything they need to know to get their
immediate job done. Now, it may be that we will decide that we would
rather make life more complicated for people writing initialization methods
in order to make the conceptual explanation shorter. That would be okay
with me if it's done for good reasons, but we shouldn't just dismiss the
other way without understanding it and understanding why I proposed it. I
have a feeling this message isn't going to explain it adequately either,
and if that happens I will apologize and follow up with a more carefully
written explanation.
One key point that I was trying to convey, and I think partially succeeded,
was the need for information hiding (abstraction) in the arguments to
make-instance and in relations among the various initialization
specifications attached to a class and its superclasses.
Another key point, which I don't think came through, was that each initarg
should be explicitly defined, and should be defined in exactly one place.
This is simply good modularity.
Some aspects of what I proposed were reacting to user complaints about the
way Flavors does it. I have the ambition of making this new standard
better than Flavors.
All this leads to the idea that initargs of types 2 and 4 (in the
nomenclature of my 16 Apr message) should be defined by methods, since
their meaning is implemented by methods. Similarly, type 3 should be
defined by slot-options, since their meaning is entirely involved with
slots. In Flavors, type 4 have the ugly property that they have to be
defined in two places, once in the method that implements them and again in
a defflavor form; it's easy to get these two places out of sync. Hence the
proposal to use the lambda-list of a defmethod as the way to define these
initargs.
I would stress this point further by saying that an object system is
going to be appreciated for its ease of use during program development.
Adding a new method is a normal thing to do and will be easier
(faster,...) on most implementation than DEFCLASS redefinition which is
a more traumatic operation (potential obsolescence of class...). Adding
a new initarg keyword to make-class for 2 or 4 does not make the class
obsolete. We shouldn't be forced to reevaluate DEFCLASS for such a small
and upwardly compatible change.
Date: Thu, 23 Apr 87 08:03:20 pst
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
From subsequent discussion, it seems as if an additional DEFCLASS
option, :DEFAULT-INITARGS is being proposed. I wonder if this
is needed, considering that a user can already specify an initialization
value via the :INITFORM option? Perhaps the metaclass ought to
attend to this? Or the :INITFORM and :DEFAULT-INITARGS options should
be merged?
This indicates that I completely failed to convey what :default-initargs is
about, and that in turn may possibly indicate that :default-initargs should
be flushed. In my proposal there are two ways to specify a default for an
initarg: at the point of definition, and remotely. To explain: when
defining an initarg one can specify right there, locally, a default value
form. For initargs that fill slots, this is the existing :initform
slot-option; no need to invent anything new there. For initargs that are
implemented by methods, this is the existing defaulting mechanism in the
lambda-list; again, no need to invent anything new. Now for remote
defaulting: here the idea is that one class defines what an initarg means,
while a second class specifies a default for it; this is :default-initargs.
When you mix the two classes together, the default meets up with the
implementation and things work. The reason remote defaulting is desirable
is twofold: (1) it's often useful when mixing classes together for one
class to customize another class by specifying initialization options, in
addition to the existing ability to customize a class by shadowing or
wrapping methods; (2) for modularity reasons, when class A customizes class
B by specifying an initarg that class B defines, class A shouldn't have to
know whether the initarg fills a slot or is implemented by a method. If
not for reason (2), remote defaulting wouldn't require a new mechanism,
because it could be implemented using the existing mechanism of :initform
for slot initargs plus call-next-method-with-arguments (proposed but not
yet accepted) for method initargs. But I think reason (2) is important.
Date: 23 Apr 87 18:24 PDT
From: Gregor.pa@Xerox.COM
What is the purpose of :initform anymore? You only need it when you
want to specify the default value for a slot that isn't set by any
initarg. This means that we have two mechanisms which do almost the
same thing -- initargs which set slots are almost a superset of
initforms. This is a sure sign of bad modularity.
On the contrary, I think it's a sign of good modularity! The two
mechanisms do almost the same thing inside the implementation, but from the
point of view of someone on the outside who doesn't know the information
that is supposed to be hidden from him by modular abstraction, they do
rather different things. I could give a longer explanation of what I mean,
but it's late, this message is already too long to ask anyone to read
carefully, and I think I would just be repeating what I said a bit earlier.
(defclass position ()
(x
y)
(:default-initargs (nil 0 x)
(nil 0 y)))
What I am trying to do is seperate what I perceive as the separate parts
of what is going on into separate places.
The reason I don't like this is that the information about a slot is no
longer all in one place. Another way of saying it is that I think that
information in defclass should be organized spatially rather than
temporally, i.e. information pertaining to one slot should be together,
rather than putting information pertaining to one phase of object creation
together. One of the ways that I think defclass is better than defflavor
is that it has done a better job of spatial organization by putting more
of the information about a slot into slot options instead of scattering it
around in various options some of which refer back to the slot by name.
I see :default-initargs being on the client side (make-instance and
such) and :initform being on the implementor side. One will supersede the
other, but conceptually they are different and should be kept different.
∂29-Apr-87 1836 Moon@STONY-BROOK.SCRC.Symbolics.COM Object creation discussion (at last!)
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 29 Apr 87 18:35:58 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 127851; Wed 29-Apr-87 21:36:13 EDT
Date: Wed, 29 Apr 87 21:36 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Object creation discussion (at last!)
To: Common-Lisp-Object-System@sail.stanford.edu
In-Reply-To: <870427013057.6.MOON@EUPHRATES.SCRC.Symbolics.COM>
Message-ID: <870429213604.0.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Mon, 27 Apr 87 01:30 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
I can see from the misunderstanding in the mail that I did an abysmal job
of communicating my ideas. I'll try to send a more comprehensible essay
tomorrow....
As you can see, I didn't get to it. I'm not going to be allowed that kind of
time for this until some time next week, so if you have comments but you were
waiting for that before sending them, open fire.
∂06-May-87 0936 kempf%hplabsc@hplabs.HP.COM Printing Objects
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 6 May 87 09:35:59 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Wed, 6 May 87 09:33:39 pdt
Received: by hplabsc ; Wed, 6 May 87 09:34:12 pdt
Date: Wed, 6 May 87 09:34:12 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705061634.AA12121@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: Printing Objects
Looking through the PRINT-OBJECT specification, there is no read macro
specified for allowing an object printed out to be read back in.
Since DEFSTRUCT has the #S read macro, it seems as if something similar
should be available for instances of classes of the default metaclass.
#O comes to mind first, but, of course, that is used by octal numbers.
Why not #@? From CLTL, pg. 352, this one looks free.
Jim Kempf kempf@hplabs.hp.com
∂06-May-87 1142 DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET Re: Printing Objects
Received: from RELAY.CS.NET by SAIL.STANFORD.EDU with TCP; 6 May 87 11:42:06 PDT
Received: from relay2.cs.net by RELAY.CS.NET id aa15417; 6 May 87 14:35 EDT
Received: from ti-csl by RELAY.CS.NET id ab23481; 6 May 87 14:31 EDT
Received: from Jenner (jenner.ARPA) by tilde id AA17350; Wed, 6 May 87 13:09:25 cdt
Message-Id: <2756311822-982351@Jenner>
Date: Wed, 6 May 87 13:10:22 CDT
From: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
To: Jim Kempf <kempf%hplabsc@hplabs.hp.com>
Cc: common-lisp-object-system@SAIL.STANFORD.EDU
Subject: Re: Printing Objects
In-Reply-To: Msg of Wed, 6 May 87 09:34:12 pdt from Jim Kempf <kempf%hplabsc@hplabs.hp.com>
Date: Wed, 6 May 87 09:34:12 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.hp.com>
Subject: Printing Objects
Looking through the PRINT-OBJECT specification, there is no read macro
specified for allowing an object printed out to be read back in.
Since DEFSTRUCT has the #S read macro, it seems as if something similar
should be available for instances of classes of the default metaclass.
#O comes to mind first, but, of course, that is used by octal numbers.
Why not #@? From CLTL, pg. 352, this one looks free.
Jim Kempf kempf@hplabs.hp.com
I don't see why #S couldn't be extended to read instances. Since #S
can only read "typed" structures (those that define a common lisp type),
the semantics wouldn't get changed.
∂06-May-87 1304 kempf%hplabsc@hplabs.HP.COM Re: Printing Objects
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 6 May 87 13:03:08 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Wed, 6 May 87 13:00:01 pdt
Received: by hplabsc ; Wed, 6 May 87 13:00:33 pdt
Date: Wed, 6 May 87 13:00:33 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705062000.AA15399@hplabsc>
To: DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET, kempf%hplabsc@hplabs.hp.com
Subject: Re: Printing Objects
Cc: common-lisp-object-system@SAIL.STANFORD.EDU
> Date: Wed, 6 May 87 09:34:12 pdt
> From: Jim Kempf <kempf%hplabsc@hplabs.hp.com>
> Subject: Printing Objects
>
> Looking through the PRINT-OBJECT specification, there is no read macro
> specified for allowing an object printed out to be read back in.
> Since DEFSTRUCT has the #S read macro, it seems as if something similar
> should be available for instances of classes of the default metaclass.
> #O comes to mind first, but, of course, that is used by octal numbers.
>
> Why not #@? From CLTL, pg. 352, this one looks free.
>
> Jim Kempf kempf@hplabs.hp.com
>
>I don't see why #S couldn't be extended to read instances. Since #S
>can only read "typed" structures (those that define a common lisp type),
>the semantics wouldn't get changed.
>
That would be OK too. Looking at the specification of #S, it could
be extended to anything with a constructor. The important point is
that the extension be noted in the CLOS specification, so it doesn't
get lost.
Jim Kempf kempf@hplabs.hp.com
∂06-May-87 2024 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Printing Objects
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 6 May 87 20:24:42 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 133775; Wed 6-May-87 23:22:56 EDT
Date: Wed, 6 May 87 23:22 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: Printing Objects
To: common-lisp-object-system@SAIL.STANFORD.EDU
In-Reply-To: <8705062000.AA15399@hplabsc>
Message-ID: <870506232253.8.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Wed, 6 May 87 13:00:33 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
> Date: Wed, 6 May 87 09:34:12 pdt
> From: Jim Kempf <kempf%hplabsc@hplabs.hp.com>
>
> Looking through the PRINT-OBJECT specification, there is no read macro
> specified for allowing an object printed out to be read back in.
>
>I don't see why #S couldn't be extended to read instances. Since #S
>can only read "typed" structures (those that define a common lisp type),
>the semantics wouldn't get changed.
That would be OK too. Looking at the specification of #S, it could
be extended to anything with a constructor. The important point is
that the extension be noted in the CLOS specification, so it doesn't
get lost.
If we wanted a thing like #S for instances of standard classes, we would
certainly use #S rather than inventing another read macro that does the
same thing as #S. However, there are some problems with #S.
Since we seem to be agreeing that the technique for creating objects
will not make the physical slots directly visible, but instead will add
a layer of abstraction, there is the issue that this transformation
may not be reversible: It may not be self-evident how to convert the
slot-values of an object into a set of arguments to make-instance that
will create an object with the same slot-values. Suppose that not all
of the slots have initargs that can initialize them.
If instead we made #S bypass make-instance's abstraction and specify
the physical slots directly, it would be a terrible violation of
modularity. What this really shows, I think, is that only a method
for the class in question can know what is the proper way to create
an equivalent instance.
In addition to this issue of slot values, I don't think the concept
of "allowing an object printed out to be read back in" is well-defined,
because the concept of reading "the same object" is not well-defined.
In the simplest cases, creating an object of the same class with
slot values "printed out and read back in" will do the job, but only
in the simplest cases. In general, an object is part of a data structure
and ripping the object out of that data structure and jamming it
into a world by itself may not be meaningful. This is the same reason
why we don't provide a general copy-object function.
I think it would make sense to have a standardized mixin class for
those simple objects whose semantics are defined entirely by the
values of their initializable slots. This class would define a
print-object method that used either #S(...) or #.(make-instance ...),
and would probably also define methods for copying and for dumping
into binary files output by compilers. This is fine; the thing I
want to be very cautious about is assuming that -all- objects should
have these methods. It's much better to package them in a mixin that
is there if you want it and not otherwise. Any suggestions for a
good name for this class? simple-object?
∂06-May-87 2202 Masinter.pa@Xerox.COM Re: Printing Objects
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 6 May 87 22:02:34 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 06 MAY 87 22:00:14 PDT
Date: 6 May 87 22:01 PDT
From: Masinter.pa@Xerox.COM
Subject: Re: Printing Objects
In-reply-to: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>'s
message of Wed, 6 May 87 23:22 EDT
To: Moon@STONY-BROOK.SCRC.Symbolics.COM
cc: common-lisp-object-system@SAIL.STANFORD.EDU
Message-ID: <870506-220014-1229@Xerox>
Of the alternatives:
a) All objects print out as #S, if you want different behavior, you
override it
b) By default, objects can't print themselves, and you have to provide a
print function or else mixin a standard class
Consider three cases:
1) object wants to print out as #S...
2) object cannot be printed really -- it doesn't make sense to "read" it
3) object wants to be printed in a special way
Case 1: a is preferable, since what you want to do is already the
default
Case 2: b is only marginally better. In alternative a, you have to
supply an error-if-you-print-me method or else you will get printing
when you shouldn't really --if your erroneously print something and
try to read it back in, alternative b gives you an error at print time,
while alternative a gives you an error later on in your program.
Case 3: it makes no difference, since you're supplying a print method.
I think Case 1 is the most common in most of the program's I've seen
anyway.
∂06-May-87 2235 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Printing Objects
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 6 May 87 22:35:41 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 133838; Thu 7-May-87 01:33:56 EDT
Date: Thu, 7 May 87 01:33 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: Printing Objects
To: common-lisp-object-system@SAIL.STANFORD.EDU
In-Reply-To: <870506-220014-1229@Xerox>
Message-ID: <870507013351.7.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 6 May 87 22:01 PDT
From: Masinter.pa@Xerox.COM
Of the alternatives:
a) All objects print out as #S, if you want different behavior, you
override it
b) By default, objects can't print themselves, and you have to provide a
print function or else mixin a standard class
This is misleading. 87-002 requires that the implementation provide a default
method. The issue in question is not whether objects can print themselves,
but what happens you feed the output of that to read. Thus alternative b
should be stated as "By default, objects print something that signals an error
when read." If I wanted to be parallel to that, but biased, I would state
alternative a as "By default, objects print something that creates a bogus
object when read."
Consider three cases:
1) object wants to print out as #S...
2) object cannot be printed really -- it doesn't make sense to "read" it
3) object wants to be printed in a special way
Case 1: a is preferable, since what you want to do is already the
default
Case 2: b is only marginally better. In alternative a, you have to
supply an error-if-you-print-me method or else you will get printing
when you shouldn't really --if your erroneously print something and
try to read it back in, alternative b gives you an error at print time,
while alternative a gives you an error later on in your program.
Not so, since Common Lisp is missing the :readably argument to WRITE.
Alternative b gives you an error at read time, not print time.
Case 3: it makes no difference, since you're supplying a print method.
I think Case 1 is the most common in most of the program's I've seen
anyway.
Not in the programs I've seen. Leaving aside endless arguments about who's
seen what programs, and turning to design rationales: I think it is better
to signal an error when there is some question what people might want,
and provide a way for them to say what they want, than to lead them down
a garden path that ends up in a mysterious blowout because the system
guessed their intention wrong. This is a general principle, but I think
it applies to this case.
∂07-May-87 0851 kempf%hplabsc@hplabs.HP.COM Re: Printing Objects
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 7 May 87 08:50:58 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 7 May 87 07:49:32 pdt
Received: by hplabsc ; Thu, 7 May 87 07:49:54 pdt
Date: Thu, 7 May 87 07:49:54 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705071449.AA25199@hplabsc>
To: Moon@STONY-BROOK.SCRC.Symbolics.COM,
common-lisp-object-system@SAIL.STANFORD.EDU
Subject: Re: Printing Objects
Leaving aside the question of whether to use #S and how to match
reading to MAKE-INSTANCE, couldn't the *PRINT-ESCAPE* switch play
a role about whether an object is printed out in a form which
is readable again? My reading of the description of *PRINT-ESCAPE*
on pg. 370 of CLtL is not clear. The first paragraph seems to
imply that this switch is supposed to primarily affect printing
of symbols with strange print names, the second paragraph seems
to imply that it serves a more general function in controlling
whether a "structure" (and by this I interpret CLtL to mean
any Common Lisp data structure, not just a DEFSTRUCT) gets printed
in a way which makes it readable again. Perhaps this switch could
be used for controlling whether the instance is printed in a
readable or nonreadable form.
Returning to the more general question, while I agree about the
desirability for compiling objects into a binary form and writing
them out, and other forms of saving objects, these will all be
machine dependent. Looking at other object-oriented languages,
one of the most attractive aspects of Objective-C to many programmers
is the Filer, a way of writing an object out in ASCII form. It provides
a kind of "lowest common denominator" persistence, and is a debugging
aid too. A programmer can send a Filer generated representation of
an Objective-C object around a local area network of diverse machines
without much extra code to do conversion from one form to another.
On the question of reading violating abstraction and who should
know how to print out an object, I think it is the metaclass rather
than the class which should know about how to print an object and
read it again. The metaclass controls the low level representation
of the object, thus should have the knowledge to decompose and write
it out, and read it in again. For FUNCALLABLE-STANDARD-CLASS, for
example, the metaclass method could do the same thing as is done
for a fundef. For STANDARD-CLASS, a default method could be provided
to read and write the object. Other metaclasses would need to supply
their own methods.
This should not, however, preclude a programmer from defining a method
on a class which writes an object in some nonreadable form.
I also agree that any read macro should go through MAKE-INSTANCE, to
avoid violating the class/object abstraction. Maybe some combination
of #S and #. could play a role, or maybe the default is simply:
#.(make-instance (class-named <name of class> <init-plist))
I think that it is important for this issue to be put into the
language spec once we have resolved it. With current Common Lisp,
there are a number of nonstandard read macros for creating the
underspecified types (e.g. #P for pathnames), which are
springing up due to need.
Jim Kempf kempf@hplabs.hp.com
∂13-May-87 1131 kempf%hplabsc@hplabs.HP.COM Object Printing Discussion
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 13 May 87 11:30:14 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Wed, 13 May 87 08:56:07 pdt
Received: by hplabsc ; Wed, 13 May 87 08:56:15 pdt
Date: Wed, 13 May 87 08:56:15 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705131556.AA06328@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: Object Printing Discussion
Continuing the object printing discussion, I'd like to address
some points brought up by Moon, and summarize things so far.
Before going further, however, I'd like to provide some
motivation for continuing
this discussion. As mentioned in a previous note, the Objective-C Filer has
proven to be a useful tool for Objective-C programmers, even though it does
have some serious disadvantages as a mechanism for storing objects.
Additionally, CommonObjects never defined a default
storage mechanism (primarily because
the issues of abstraction violation were not fully thought out) and it has
proven to be a perennial problem. Binary storage mechanisms based on compiler
modifications, databases and the like are all interesting, but some base
level hooks and a simple default storage mechanism using existing Common Lisp
read macros where possible and ASCII text can simplify applications development
and provide backward compatibility with DEFSTRUCT. I'm sure, if it is
not provided, someone will to question why DEFSTRUCT's have
a readable storage representation and objects do not.
On to the discussion:
>Since we seem to be agreeing that the technique for creating objects
>will not make the physical slots directly visible, but instead will add
>a layer of abstraction, there is the issue that this transformation
>may not be reversible: It may not be self-evident how to convert the
>slot-values of an object into a set of arguments to make-instance that
>will create an object with the same slot-values. Suppose that not all
>of the slots have initargs that can initialize them.
I agree with the need for a layer of abstraction, however, the level of
MAKE-INSTANCE may be too high. In particular, if, as Moon's comments indicate,
the defined initialization protocol for the class will not accomodate
initializing an object with the current slot value when read back in,
it would not be possible to write out an object's slot values and read
them back in using MAKE-INSTANCE. An example would be when no initarg
is defined for a slot (i.e., it is not initializable from MAKE-INSTANCE).
>In addition to this issue of slot values, I don't think the concept
>of "allowing an object printed out to be read back in" is well-defined,
>because the concept of reading "the same object" is not well-defined.
>In the simplest cases, creating an object of the same class with
>slot values "printed out and read back in" will do the job, but only
>in the simplest cases. In general, an object is part of a data structure
>and ripping the object out of that data structure and jamming it
>into a world by itself may not be meaningful. This is the same reason
>why we don't provide a general copy-object function.
I think you could make this argument for any Lisp data structure, including
lists, vectors, or what have you. Perhaps more strongly for objects, since
they tend to be more highly structured. I certainly agree it may not be
meaningful to write out an object and read it back in, but, in the default
case, I think the metaclass could provide some kind of meaning, which
could then be customized on a class by class (or metaclass by metaclass)
basis. In cases where it is not possible to provide meaning (like
writing out packages and fundefs in Common Lisp), the #< read macro
can be used to prohibit reading the representation back in.
>I think it would make sense to have a standardized mixin class for
>those simple objects whose semantics are defined entirely by the
>values of their initializable slots. This class would define a
>print-object method that used either #S(...) or #.(make-instance ...),
>and would probably also define methods for copying and for dumping
>into binary files output by compilers. This is fine; the thing I
>want to be very cautious about is assuming that -all- objects should
>have these methods. It's much better to package them in a mixin that
>is there if you want it and not otherwise. Any suggestions for a
>good name for this class? simple-object?
As mentioned in a previous note, I think that control of object representation
should be left to the metaclass, and therefore this functionality should
be part of the metaobject protocol. The metaobject protocol controls how
objects and classes get created within memory, and thus it seems logical
that it should also control how objects move out to disc.
. . . . . .
Lacking any concensus on object creation, it's difficult to outline a
detailed proposal as to what should be done. Here's a summary of
my thinking on the issue so far:
1) CLOS should specify a default printable object representation which
is readable again, if only because programmers find it useful.
2) This representation should be ASCII and should use existing Common Lisp
read macros where possible, to facilitate portability and backward
compatibility.
3) The abstraction level should be below MAKE-INSTANCE, so that slots
which are not initable through MAKE-INSTANCE initargs can still be
initialized, but above the level of simply setting the slot, so the
class can customize initialization from a dumped object if desired.
4) The hooks should be part of the metaobject protocol, since the
metaobject protocol controls the representation of classes and
instances.
With regard to 3) and 4), possibly the issue of conversion of slot
values could be dealt with via a method on the STANDARD-SLOT-DESCRIPTION
class. However, I'll forgo any detailed proposals until hearing whether
there is any agreement about the overall issues.
Jim Kempf kempf@hplabs.hp.com
∂13-May-87 1323 Gregor.pa@Xerox.COM Re: Object Printing Discussion
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 13 May 87 13:22:56 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 13 MAY 87 12:51:11 PDT
Date: 13 May 87 12:50 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Object Printing Discussion
In-reply-to: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>'s message of Wed,
13 May 87 08:56:15 pdt
To: kempf%hplabsc@hplabs.HP.COM
cc: common-lisp-object-system@sail.stanford.edu
Message-ID: <870513-125111-2498@Xerox>
Be warned, I am going to (mostly) dump on using printing for dumping.
The reason defstruct has a readable representation for printed objects
is because defstruct is broken in this (and many other) regard. I
believe the default printed representation of defstruct types lulls
programmers into a false sense of believing that the problem of dumping
and restoring has been solved for them when in fact, that is not at all
true.
In my mind, printing an object for the user read its 'printed
representation' and dumping an object so that some other program can
restore it later are two completely different operations. In addition,
depending on the application or mode, there may be many different ways
to do each of these.
Lets just look at dumping/restoring, what are some of the issues:
- circularity, how to deal with it?
- pointers to special "ground" objects which shouldn't be dumped but
which
should be "re-grounded" when the object is restored.
- restoring an object but not all the objects it points to
None of these questions is terribly hard, but they all have very
different answers depending on the specific application. Whats more,
none of these have to do with efficiency per se. I can add efficeincy
as another problem, it only makes this more complicated.
- efficiency of dump format. Certainly the #S format is about the least
efficient
dump format imaginable. It takes a lot of space, and it takes a lot
of work at
dump and restore time.
So I guess my opinion is that it would be a mistake to try to
standardize a 'generally useful for dumping' print function. Certainly
any class or metaclass which wants to can provide a different method for
print-object which would be the base of a whole dumping/restoring
sub-protocol. So the hook is there for people to do whatever they want.
But I think we would be doing them a diservice to pretend that we had
provided them a general solution to this problem.
Here is a related question?
What happens if an object appears as a constant in a piece of code that
is being compiled to a file? CLtL certainly is not clear on what
happens if a defstruct-defined structure appears in such a place. Is
print-object what you would like to call here??
∂13-May-87 1444 DLW@ALDERAAN.SCRC.Symbolics.COM Object Printing Discussion
Received: from [192.10.41.109] by SAIL.STANFORD.EDU with TCP; 13 May 87 14:44:22 PDT
Received: from CHICOPEE.SCRC.Symbolics.COM by ALDERAAN.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 81287; Wed 13-May-87 17:31:55 EDT
Date: Wed, 13 May 87 17:31 EDT
From: Daniel L. Weinreb <DLW@ALDERAAN.SCRC.Symbolics.COM>
Subject: Object Printing Discussion
To: kempf%hplabsc@hplabs.HP.COM, common-lisp-object-system@sail.stanford.edu
In-Reply-To: <8705131556.AA06328@hplabsc>
Message-ID: <870513173115.5.DLW@CHICOPEE.SCRC.Symbolics.COM>
Date: Wed, 13 May 87 08:56:15 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
1) CLOS should specify a default printable object representation which
is readable again, if only because programmers find it useful.
The point is that it's not clear what "readable" means, and how useful
it is. You'd have to be more careful about how this is defined. What
if the value of one of the slots is a compiled code object? But even if
all the values are symbols, you still have to make sure that people
realize that reading this printed representation can only be said to
"create a new instance which, in some respects, is like the instance
that got printed", which isn't really guaranteeing very much.
2) This representation should be ASCII and should use existing Common Lisp
read macros where possible, to facilitate portability and backward
compatibility.
(Not ASCII, but the CL character set, which is more restrictive than
that. Portability to the 370, remember.)
4) The hooks should be part of the metaobject protocol, since the
metaobject protocol controls the representation of classes and
instances.
I don't agree with this; it would be a real pain in the neck, and
overkill, to have to define a whole new metaclass just to say how an
instance is printed. Defining a method is far easier.
∂14-May-87 1322 kempf%hplabsc@hplabs.HP.COM Re: Printing Objects
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 14 May 87 13:22:01 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 14 May 87 13:21:05 pdt
Received: by hplabsc ; Thu, 14 May 87 13:21:23 pdt
Date: Thu, 14 May 87 13:21:23 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705142021.AA26108@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: Re: Printing Objects
Cc: kempf%hplabsc@hplabs.HP.COM
From Gregor:
>Be warned, I am going to (mostly) dump on using printing for dumping.
>
>The reason defstruct has a readable representation for printed objects
>is because defstruct is broken in this (and many other) regard. I
>believe the default printed representation of defstruct types lulls
>programmers into a false sense of believing that the problem of dumping
>and restoring has been solved for them when in fact, that is not at all
>true.
From Dan Weinreb:
> 4) The hooks should be part of the metaobject protocol, since the
> metaobject protocol controls the representation of classes and
> instances.
>
>I don't agree with this; it would be a real pain in the neck, and
>overkill, to have to define a whole new metaclass just to say how an
>instance is printed. Defining a method is far easier.
Yow! Ok, let's forget it then. The default PRINT-OBJECT can print
out in a nonreadable form, and it's up to the user to take care
of printing in a class or metaclass specific way.
From Gregor:
>Here is a related question?
>
>What happens if an object appears as a constant in a piece of code that
>is being compiled to a file? CLtL certainly is not clear on what
>happens if a defstruct-defined structure appears in such a place. Is
>print-object what you would like to call here??
In fact, CLtL doesn't specify how a constant ANYTHING gets compiled into
file. It doesn't even specify that two references to a constant
which are EQ during compilation will be EQ after the compiled file
is loaded. The only thing which my reading of CLtL seems to indicate
will be EQ is an interned symbol, and then only if the package exists
in the load environment.
I don't think you can realistically expect PRINT-OBJECT to be of use
here, since everyone will have a different low level representation
within compiled code files. The motivation for having a readable format
was for easy exchange of objects between machines, and the ability
to store objects in some default format, like DEFSTRUCT. But, as was
pointed out, a general solution is probably still a research question.
For examining the internals of an object, DESCRIBE (87-002, pg. 2-37)
or INSPECT (CLtL, pg. 442, but not in 87-002) could be used.
Jim Kempf kempf@hplabs.hp.com
∂15-May-87 1110 Gregor.pa@Xerox.COM optimization versus constructors
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 15 May 87 11:10:32 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 15 MAY 87 11:07:52 PDT
Date: 15 May 87 11:07 PDT
From: Gregor.pa@Xerox.COM
Subject: optimization versus constructors
To: Common-Lisp-Object-System@Sail.Stanford.edu
Message-ID: <870515-110752-4939@Xerox>
Danny and I have been thinking about initialization and are picking away
at parts of the problem we don't understand. Specifically, I was trying
to remember what the :constructor option was really for. I remembered
that:
- it isn't really just an abbreviation for a defun and a call to
make-instance since it can set slots which are not settable by initargs.
- even if it was just an abbreviation for a defun with a call to
make-instance, the constructors generated by the :constructor option
would be much faster than the ones defined by calling make-instance by
hand.
This message addresses the second of these 2 points. Specifically, I
will show a simple (even trivial) technique which reduces optimizing
calls to make-instance to exactly the same problem as optimizing
constructors produced by :constructor option. This is important because
it means that we can think about constructors only in terms of their
behavior, they are not needed for performance anymore.
The basic idea is that a call to make-instance with a constant first
argument and constant key (even numbered) args can be treated as a
dynamic definition of an :constructor with some gensymed name.
So that in the form
(progn .. (make-instance 'boat :speed 10) ..)
the call to make-instance can be converted to something like:
(progn .. (#:G001 10) ..)
and the class gets updated as if it had had a :constructor option
(:constructor #:g001 (speed)).
This shows that whatever optimization can be gotten from the
:constructor option can also be gotten from calls to make-instance (at
least the calls to make-instance for which you could have used a
constructor).
∂15-May-87 1240 kempf%hplabsc@hplabs.HP.COM Why is MAKE-INSTANCE not generic?
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 15 May 87 12:40:34 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Fri, 15 May 87 12:39:40 pdt
Received: by hplabsc ; Fri, 15 May 87 12:39:32 pdt
Date: Fri, 15 May 87 12:39:32 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705151939.AA11025@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: Why is MAKE-INSTANCE not generic?
87-002 says that MAKE-INSTANCE is a function, and not a generic
function. Why is this? In particular, a metaclass may want
to specialize MAKE-INSTANCE to a particular metaclass-dependent
instance creation procedure. The instance "creation" procedure
might not fit into the ALLOCATE-INSTANCE/INITIALIZE pattern
which MAKE-INSTANCE currently uses. I realize that instance
creation is, as yet, not completely specified, but wanted to
bring up the point anyway.
Jim Kempf kempf@hplabs.hp.com
∂15-May-87 1315 kempf%hplabsc@hplabs.HP.COM Re: Why in MAKE-INSTANCE not generic?
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 15 May 87 13:15:24 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Fri, 15 May 87 13:14:28 pdt
Received: by hplabsc ; Fri, 15 May 87 13:14:48 pdt
Date: Fri, 15 May 87 13:14:48 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705152014.AA11627@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: Re: Why in MAKE-INSTANCE not generic?
There seems to be a slight discrepency between 87-002 and 87-003 on
this point. 87-002, pg. 2-44 implies that MAKE-INSTANCE is a programmer
interface function, 87-003, pg. 3-7 implies that it is a method
which is part of the metaobject protocol.
Jim Kempf kempf@hplabs.hp.com
∂15-May-87 1648 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Why in MAKE-INSTANCE not generic?
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 15 May 87 16:48:43 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 141322; Fri 15-May-87 19:37:40 EDT
Date: Fri, 15 May 87 19:36 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: Why in MAKE-INSTANCE not generic?
To: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
cc: common-lisp-object-system@sail.stanford.edu
In-Reply-To: <8705152014.AA11627@hplabsc>
Message-ID: <870515193649.3.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Fri, 15 May 87 13:14:48 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
There seems to be a slight discrepency between 87-002 and 87-003 on
this point. 87-002, pg. 2-44 implies that MAKE-INSTANCE is a programmer
interface function, 87-003, pg. 3-7 implies that it is a method
which is part of the metaobject protocol.
As you may have noticed, the protocol for creating objects hasn't been
defined yet. Anything that's in the documents now can't be relied upon.
∂15-May-87 1715 Moon@STONY-BROOK.SCRC.Symbolics.COM optimization versus constructors
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 15 May 87 17:15:05 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 141385; Fri 15-May-87 20:14:21 EDT
Date: Fri, 15 May 87 20:13 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: optimization versus constructors
To: Common-Lisp-Object-System@Sail.Stanford.edu
In-Reply-To: <870515-110752-4939@Xerox>
Message-ID: <870515201336.5.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 15 May 87 11:07 PDT
From: Gregor.pa@Xerox.COM
Danny and I have been thinking about initialization and are picking away
at parts of the problem we don't understand. Specifically, I was trying
to remember what the :constructor option was really for.
....
This shows that whatever optimization can be gotten from the
:constructor option can also be gotten from calls to make-instance (at
least the calls to make-instance for which you could have used a
constructor).
I agree that the :constructor mechanism could be replaced by a complicated
mechanism involving compile time optimizations of recognized patterns of
constant arguments to make-instance, with some way to get around the fact
that constructors can initialize any slot but we don't want make-instance
to be able to do that. There is some trickiness required to make this
compile-time optimized code get recompiled whenever the class's structure
is changed.
I don't remember who put constructors in, but I assume the idea was that
the other way of doing it was too complicated. It's probably a good model
for thinking about the semantics and making sure that constructors and
make-instance behave consistently, but we probably don't want to require
implementations to work that way.
∂20-May-87 1934 Pavel.pa@Xerox.COM CLOS vs. subtypes of FLOAT
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 20 May 87 19:34:14 PDT
Received: from Salvador.ms by ArpaGateway.ms ; 20 MAY 87 18:52:30 PDT
Date: Wed, 20 May 87 18:52:23 PDT
From: Pavel.pa@Xerox.COM
Subject: CLOS vs. subtypes of FLOAT
To: Common-Lisp-Object-System@SAIL.Stanford.Edu
Cc: Pavel.pa@Xerox.COM
Message-ID: <870520-185230-2840@Xerox>
Here it is, finally, my proposal(s) for the treatment of the subtypes of
FLOAT for discrimination in CLOS.
The issue, to refresh folks' memories, is what to do with code like the
following:
(defmethod foo ((x single-float)) ...)
(defmethod foo ((x double-float)) ...)
There are three major questions:
1) Is this code legal at all? That is, is it okay to discriminate on
the subtypes of FLOAT?
2) What is the effect of such code in an implementation that does not
represent the two types differently (such as one that has only one
representation of floating-point numbers)? Is it legal in such
implementations?
3) Which of the symbols naming subtypes of FLOAT also name classes?
Can this vary from implementation to implementation?
I have come up with three different proposals to answer these questions.
I will first lay them out and then discuss their relative advantages and
disadvantages.
Proposal 1 "NONE":
It is illegal to discriminate on any of the subtypes of FLOAT. None
of them name classes at all, in any implementation.
Proposal 2 "SOME":
In a given implementation, exactly as many of the subtype-symbols
name classes as there are different representations of floating-point
numbers. The ones that name classes are derived from the list of
allowable representation-naming schemes given on pages 18-19 of CLtL:
-- If there is only one representation, then SINGLE-FLOAT names a
class.
-- If there are exactly two representations, then either SHORT-FLOAT
and SINGLE-FLOAT, or SINGLE-FLOAT and DOUBLE-FLOAT, name classes.
-- If there are exactly three representations, then either
SHORT-FLOAT and SINGLE-FLOAT and DOUBLE-FLOAT, or SINGLE-FLOAT
and DOUBLE-FLOAT and LONG-FLOAT, name classes.
-- If four representations exist, then all four symbols name classes.
The classes named by such symbols are all subclasses of FLOAT. Clearly,
those symbols that do not name classes cannot be used for
discrimination.
Proposal 3 "ALL":
All of the subtype-symbols name classes, and all of those classes are
subclasses of FLOAT. In some implementations, some of the classes named
by those symbols are "synonyms" for other classes, according to the
following scheme (again derived from pages 18-19 of CLtL):
-- If there is only one representation, then the classes named by
SHORT-FLOAT, DOUBLE-FLOAT and LONG-FLOAT are all synonyms for the
class named by SINGLE-FLOAT.
-- If there are exactly two representations, then either
- the classes named by DOUBLE-FLOAT and LONG-FLOAT are synonyms
for the class named by SINGLE-FLOAT, or
- the class named by SHORT-FLOAT is a synonym for the class named
by SINGLE-FLOAT and the class named by LONG-FLOAT is a synonym
for the class named by DOUBLE-FLOAT
-- If there are exactly three representations, then either
- the class named by LONG-FLOAT is a synonym for the class named
by DOUBLE-FLOAT, or
- the class named by SHORT-FLOAT is a synonym for the class named
by SINGLE-FLOAT
-- If there are four representations, then no classess are synonyms
of others.
If a class A is a synonym of another class B, then A and B are not EQ,
they have different names, and they may have different metaclasses. No
instances may exist of class A. Defining a method on a generic function
F that discriminates on A has the same general effect as defining one
that discriminates on B. However, if a method already exists on F that
discriminates on B or a different synonym of B (i.e., not A), then a
correctable error is signalled, allowing the user to choose which one of
the two methods will remain on F.
Under the NONE proposal, the pair of DEFMETHOD's above would be illegal
in all implementations.
Under the SOME proposal, the pair would be legal in those
implementations that had distinct representations called SINGLE-FLOAT
and DOUBLE-FLOAT. In other implementations, an "Unknown class name"
error would be signalled.
Under the ALL proposal, the pair would compile and evaluate quietly and
correctly in those implementations that had distinct representations
called SINGLE-FLOAT and DOUBLE-FLOAT. In other implementations, a
correctable error would be signalled upon encountering the second
DEFMETHOD and the user would have to choose between the two methods.
I have been convinced by conversations with a number of floating-point
users around here that algorithms exist that can go much more quickly if
they can be guaranteed a certain minimum amount of precision in the
numbers. These algorithms would have to make checks for certain
conditions only if less precision is available. While these programs
would have to be conditionalized (using #+/#-) for different
implementations to patch in the name of the sufficiently-precise
representation (since CLtL does not give a required bit count for each
representation), this isn't very hard to do and should be allowed.
One can also imagine users who wish to use the very same source code for
some floating-point-intensive computation in two methods, one for
SINGLE-FLOAT arguments and one for DOUBLE-FLOAT arguments. The idea
here is that the compiler could generate much better code given the
implicit declaration of the argument type. Each of the two copies might
perform much better than an undeclared version. This user would be
letting the object system make a single check upon entry to the generic
function before dispatching to the representation-specific version of
the code.
I am convinced by arguments like these that reasonable uses exist for
discrimination on subtypes of FLOAT. Thus, I believe that the NONE
proposal is a bad idea.
The SOME proposal is very easy to implement, but has the (perhaps only
aesthetic) flaw that the existence of classes for certain built-in types
would vary between implementations. I find this notion disturbing and
would prefer not to see it.
The ALL proposal solves this problem but introduces, for almost all
implementations, the extra mechanism implied by the synonym classes. It
may be that this could be very easily implemented, but Gregor would
probably know better. An alternative to synonym classes would be making
the name -> class mapping be many-to-one. Gregor claims that this
cannot be allowed, but I'm not sure that I understand why. Another way
to avoid synonyms is to make the classes that would be synonyms into
subclasses of the other class. This, on the other hand, has the problem
that methods defined on such classes would never be called, since no
instances of them can be created. It also establishes an asymmetric
subclass relation for pairs with a symmetric subtype relation.
This is getting pretty long for such a relatively minor issue. I'll
stop here and see if anyone can make any sense of this.
Pavel
∂21-May-87 1228 Pavel.pa@Xerox.COM Re: CLOS vs. subtypes of FLOAT
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 21 May 87 12:27:47 PDT
Received: from Salvador.ms by ArpaGateway.ms ; 21 MAY 87 12:20:51 PDT
Date: Thu, 21 May 87 12:20:50 PDT
From: Pavel.pa@Xerox.COM
Subject: Re: CLOS vs. subtypes of FLOAT
In-reply-to: "Masinter's message of 21 May 87 12:07 PDT"
To: Masinter.pa@Xerox.COM
Cc: Common-Lisp-Object-System@SAIL.Stanford.Edu
Message-ID: <870521-122051-1382@Xerox>
Date: 21 May 87 12:07 PDT
From: Masinter.pa
You omitted the possibility where all the classes
exist in all implementations, but that some of the
classes might be empty (have no instances) in some
implementations.
In putting together the proposals, I had two (unfortunately unstated) design criteria:
1) Discrimination on the subtypes of FLOAT should be allowed
2) Discriminations that cannot work in a given implementation
(due to collapsing together some of the subtypes) should signal
an error so that the user doesn't lose quietly.
Proposal NONE loses on the first criterion and your proposal violates the second.
Pavel
∂21-May-87 1227 Masinter.pa@Xerox.COM Re: CLOS vs. subtypes of FLOAT
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 21 May 87 12:27:38 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 21 MAY 87 12:08:02 PDT
Date: 21 May 87 12:07 PDT
From: Masinter.pa@Xerox.COM
Subject: Re: CLOS vs. subtypes of FLOAT
In-reply-to: Pavel.pa's message of Wed, 20 May 87 18:52:23 PDT
To: Pavel.pa@Xerox.COM
cc: Common-Lisp-Object-System@SAIL.Stanford.Edu
Message-ID: <870521-120802-1365@Xerox>
You omitted the possibility where all the classes exist in all
implementations, but that some of the classes might be empty (have no
instances) in some implementations.
∂21-May-87 1338 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: CLOS vs. subtypes of FLOAT
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 21 May 87 13:38:33 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 146801; Thu 21-May-87 16:37:36 EDT
Date: Thu, 21 May 87 16:37 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: CLOS vs. subtypes of FLOAT
To: Common-Lisp-Object-System@SAIL.Stanford.Edu
In-Reply-To: <870521-120802-1365@Xerox>
Message-ID: <870521163738.8.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 21 May 87 12:07 PDT
From: Masinter.pa@Xerox.COM
You omitted the possibility where all the classes exist in all
implementations, but that some of the classes might be empty (have no
instances) in some implementations.
Unfortunately this elegant-sounding choice can't be taken without
changing Common Lisp incompatibly. The problem is that Common Lisp
specifies (CLtL p.19) that in an implementation without short-floats,
(typep x 'short-float) does the same thing as (typep x 'single-float),
rather than always returning nil. We want to keep typep consistent
with class-instance relationships, to avoid giving Common Lisp too
subtly-incompatible type systems.
∂21-May-87 1909 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 21 May 87 19:08:50 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 21 MAY 87 18:22:41 PDT
Date: 21 May 87 18:22 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Object creation discussion (at last!)
In-reply-to: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>'s
message of Mon, 27 Apr 87 01:30 EDT
To: Moon@STONY-BROOK.SCRC.Symbolics.COM
cc: Common-Lisp-Object-System@sail.stanford.edu
Message-ID: <870521-182241-1963@Xerox>
I have elided parts of your message which I am not going to comment on
directly.
Date: Mon, 27 Apr 87 01:30 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Complexity and simplicity are partly matters of taste, and
largely matters of point of view.
I think this notion of what complexity and simplicity are is very
important to this discussion so, despite the fact that this is a
potential tarpit, I will try to make some comments about this.
I try to take the point of view
of the majority of programmers, who are using the outer interfaces
of the system without necessarily understanding everything that's
going on inside. No matter how beautifully we explain it, most
programmers simply won't read beyond the point where they think
they know everything they need to know to get their immediate job
done.
I agree.
Now, it may be that we will decide that we would rather make
life more complicated for people writing initialization methods in
order to make the conceptual explanation shorter.
Another way of saying this is "it may be that we will decide that we
would rather make it syntactically more complicated for people writing
initialization methods in order to make the conceptual explanation of
the system simpler". Let me try to explain why I would say it that way.
Because I agree with you that people will not read any more of the
documentation than they think they can get away with, I think it is
important for people to be able to develop mental models of the system
which have significant predictive power. By predictive power I mean
(among other things) it should be possible for a user to figure out how
to do something they haven't done before based on what they already
know. This means I believe it is often more important for a user to be
able to figure out how to do something than it is for there to be some
concise abbreviation for doing this 'new trick'.
Thus I believe that an important measure of a system's simplicity is the
ease with which users can develop a model of the system which has this
kind of predictive power.
In the example of initialization methods, my esthetic says that it would
be better for someone to be able to figure out how to write
initialization methods based on what they already know about ordinary
methods (without having to read any additional documentation) than it
would be for there to be some concise syntax for defining initialization
methods.
Note that this biases 'ease' away from the expert programmer. For the
record, I acknowledge this and this is consistent with my belief that it
is very difficult for an expert programmer to design something which is
really easy to understand. Expert programmers tend to design things
which have lots of 'bells and whistles' which make things simpler for
the expert user, but more complicated for everyone else. I will cite as
examples the Interlisp-D and LispM systems.
One key point that I was trying to convey, and I think
partially succeeded, was the need for information hiding
(abstraction) in the arguments to make-instance and in relations
among the various initialization specifications attached to a class
and its superclasses.
I agree that this is important, and your message does a good job of
collecting a lot of the reasons why this abstraction is important.
Remote initarg defaulting is related to this and your message does a
good job of describing why that is important.
Another key point, which I don't think came through, was that
each initarg should be explicitly defined, and should be defined in
exactly one place. This is simply good modularity.
I am not sure I agree with this. In fact, there are places later in
your message where you seem to disagree with this for the same reasons I
do.
Specifically, its not entirely clear to me what it means to 'define an
initarg'. Defining an initarg can mean specifying that this is a legal
initarg for a class (and its subclasses), or it can mean specifying what
the implementation of the processing this initarg should be. This is
like the protocol/implementation distinction. It would certainly be
'clean' for some sense of clean to require that legal initargs for a
class be specified in on option, and then there be other independent
mechanisms for specifying the implementation of those initargs
(corresponding to your types 1-4). One might argue that this is
cumbersome, but its important to understand that it would be simpler in
some senses.
--- reference ---
For reference, I am including the part of your message of April 16th
which defines initarg types 1-4.
From: David A. Moon
Date: Thu, 16 Apr 87 00:22 EDT
1. :allow-other-keys serves its usual function, as in all
&key argument lists. It isn't possible to define
additional initargs for step 1.
2. Initargs that control storage allocation are defined
by defining an allocate-instance method that accepts
the initarg as an &key argument. For example, in
systems with areas :area is an initarg for step 2.
The standard does not require any initargs to exist
for step 2.
3. Initargs that fill slots are defined by the :initarg
slot-option.
4. Initargs for initialization methods are defined by
defining an initialize-instance method that accepts
the initarg as an &key argument.
--- reference ---
All this leads to the idea that initargs of types 2 and 4 (in
the nomenclature of my 16 Apr message) should be defined by
methods, since their meaning is implemented by methods. Similarly,
type 3 should be defined by slot-options, since their meaning is
entirely involved with slots. In Flavors, type 4 have the ugly
property that they have to be defined in two places, once in the
method that implements them and again in a defflavor form; it's
easy to get these two places out of sync. Hence the proposal to
use the lambda-list of a defmethod as the way to define these
initargs.
As I said above, 'defining' in this paragraph can have two meanings.
The part of 'defining' which implements the behavior of the initarg
should definitely be close to 'the place that behavior affects or
happens'. So, slot setting initargs should have their behavior defined
in slots, initargs handled by methods should be in methods etc.
Along with this, I tried to eliminate clunky syntax from
initialization methods, hence the elimination of &allow-other-keys
and the elimination of having to write :before all the time. If
this is too confusing, we could invent a new syntax that both
defines initargs and defines the method that implements them.
Clearly this is the weakest part of my proposal.
As I said in my comments on what constitutes simplicity, I don't
necessarily agree that minor improvements in syntax (like removing
&allow-other-keys) always make for improvements in simplicity.
We could obviously simplify things a lot by getting rid of the
:constructor option to defclass. I didn't put it in, at least not
this year. I do think it ought to remain, in spite of its inherent
complexity in any initialization proposal (previous ones I've seen
have glossed over this rather than solving it), because I believe
many users will find it quite useful.
I don't know whether I like constructors yet or not. In my message last
week I tried to show that I think constructors are deceptively confsuing
because they contain a hidden performance optimization. I also think
they are deceptively confusing because the rules for breaking the
lambda-list down into initargs and setf of slot-value(s) are
complicated. Because :constructors are just an abbreviation for a defun
with a make instance and some setf of slot-values, I have separated them
from the rest of initialization for the time being. I want to think
about putting them back once we understand the rest better.
Date: Wed, 22 Apr 87 13:42 PDT
From: Gregor.pa@Xerox.COM
The special method combination type for initialize
instance adds considerable conceptual overhead for very little
functional gain.
The goal was not functional gain, that is, the ability to
program something you couldn't program before, but rather syntactic
simplicity. Perhaps in the end we'll decide it's not worth it, but
I'd like us to keep considering the question a bit longer.
My description of simplicity at the beginning of this message shows why
I think this extra method-combination type is not a net gain.
Date: Wed, 22 Apr 87 17:28 PDT
From: Gregor.pa@Xerox.COM
The default-initargs defclass option serves two
purposes. It specifies all the initargs which can be passed to
make-instance of this class, and it specifies default values
for some of those initargs.
This is an important modularity mistake, in my opinion. By
combining these two things, which ought to be separate, you have
lost the ability for one class to specify a default value for an
initarg defined by another class. If specifying a default value
always defines an initarg, there is no way to check the consistency
of the set of initargs with default values specified against the
set of initargs actually defined. If there is a misspelling, the
default value will simply be discarded, since no method will
receive it and do something with it.
I agree with this reasoning. This is the reasoning I was making
reference to earlier in this message when I said that there were reasons
not to 'define' initargs in one place.
∂22-May-87 0627 @RELAY.CS.NET:DUSSUD%Jenner@TI-CSL.CSNET Re: CLOS vs. subtypes of FLOAT
Received: from RELAY.CS.NET by SAIL.STANFORD.EDU with TCP; 22 May 87 06:27:38 PDT
Received: from relay2.cs.net by RELAY.CS.NET id af20247; 22 May 87 9:21 EDT
Received: from ti-csl by RELAY.CS.NET id aj07513; 22 May 87 9:16 EDT
Received: by tilde id AA13337; Fri, 22 May 87 08:10:19 CDT
Message-Id: <2757676277-14030516@Jenner>
Date: Fri, 22 May 87 08:11:17 CDT
From: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
To: Pavel.pa@XEROX.COM
Cc: Common-Lisp-Object-System@SAIL.STANFORD.EDU
Subject: Re: CLOS vs. subtypes of FLOAT
In-Reply-To: Msg of Wed, 20 May 87 18:52:23 PDT from Pavel.pa@xerox.com
Date: Wed, 20 May 87 18:52:23 PDT
From: Pavel.pa@xerox.com
Subject: CLOS vs. subtypes of FLOAT
I agree with you that proposal 1(NONE) is not desirable. If we pick 1, then
the choice of making float subtypes classes will be left to each
implementation, creating confusion for users.
Proposal 2(SOME), while OK on one implementation, will portable
applications make hard to develop. Users will have to conditionalize
the whole definition of some methods and the name of the float
specializers for some others.
Proposal 3(ALL), makes life of the user easier, but confront us to a new
problem, do we want to introduce class-synonyms. If we are to adopt 3,
then I think that class-synonyms should be standardized for general use.
Pavel brushes up two ways to address class-synonyms:
A:
If a class A is a synonym of another class B, then A and B are not EQ,
they have different names, and they may have different metaclasses. No
instances may exist of class A. Defining a method on a generic function
F that discriminates on A has the same general effect as defining one
that discriminates on B. However, if a method already exists on F that
discriminates on B or a different synonym of B (i.e., not A), then a
correctable error is signalled, allowing the user to choose which one of
the two methods will remain on F.
B:
An alternative to synonym classes would be making the name -> class
mapping be many-to-one.
B: seems a lot simpler than A:. It does not affect class objects, just
the name space. It opens up some issues for class-redefinition though.
I don't like 3A:
Another way to avoid synonyms is to make the classes
that would be synonyms into subclasses of the other class. This, on the
other hand, has the problem that methods defined on such classes would
never be called, since no instances of them can be created. It also
establishes an asymmetric subclass relation for pairs with a symmetric
subtype relation.
Because it would break the subtypep-subclassp identity.
Patrick.
∂22-May-87 0725 DLW@ALDERAAN.SCRC.Symbolics.COM Re: Object creation discussion (at last!)
Received: from [192.10.41.109] by SAIL.STANFORD.EDU with TCP; 22 May 87 07:25:35 PDT
Received: from CHICOPEE.SCRC.Symbolics.COM by ALDERAAN.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 84672; Fri 22-May-87 10:07:17 EDT
Date: Fri, 22 May 87 10:06 EDT
From: Daniel L. Weinreb <DLW@ALDERAAN.SCRC.Symbolics.COM>
Subject: Re: Object creation discussion (at last!)
To: Gregor.pa@Xerox.COM, Moon@STONY-BROOK.SCRC.Symbolics.COM
cc: Common-Lisp-Object-System@sail.stanford.edu
In-Reply-To: <870521-182241-1963@Xerox>
Message-ID: <870522100649.2.DLW@CHICOPEE.SCRC.Symbolics.COM>
Line-fold: No
Date: 21 May 87 18:22 PDT
From: Gregor.pa@Xerox.COM
From: Moon
Along with this, I tried to eliminate clunky syntax from
initialization methods, hence the elimination of &allow-other-keys
and the elimination of having to write :before all the time. If
this is too confusing, we could invent a new syntax that both
defines initargs and defines the method that implements them.
Clearly this is the weakest part of my proposal.
As I said in my comments on what constitutes simplicity, I don't
necessarily agree that minor improvements in syntax (like removing
&allow-other-keys) always make for improvements in simplicity.
This kind of thing is a real bear. I think you're both right. I've
been caught on the horns of this dilemma many times before. It's
frustrating, because I always feel that you're damned if you do and
damned if you don't. Either you have to put in special-case material
that increases conceptual complexity, or you have to make everybody put
up with a clumsy syntax. This seems to be one of those cases where it's
hard to avoid one evil or the other. I don't see any decision criterion
that's clearly overriding. If anyone has any new insights into this
generic problem, I'd love to hear them.
∂22-May-87 1002 kempf%hplabsc@hplabs.HP.COM Arguments to CALL-NEXT-METHOD
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 22 May 87 10:02:03 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Fri, 22 May 87 10:01:28 pdt
Received: by hplabsc ; Fri, 22 May 87 10:00:54 pdt
Date: Fri, 22 May 87 10:00:54 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705221700.AA01346@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: Arguments to CALL-NEXT-METHOD
The ANSI 87-002 CLOS spec, pg. 2-6-2-7 states that rebinding of
argument parameters for CALL-NEXT-METHOD is not permitted, but
that a proposed extension is to allow it to accept arguments.
I would like to inquire about the reason for not allowing
parameter rebinding, and propose that, if no important arguments
against it are forthcoming, the proposed extension be accepted.
The reason is that, in the process of implementing COOL, I have
found need to do this.
Jim Kempf kempf@hplabs.hp.com
∂22-May-87 1116 Gregor.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 22 May 87 11:16:33 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 22 MAY 87 11:04:43 PDT
Date: 22 May 87 11:04 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>'s message of Fri,
22 May 87 10:00:54 pdt
To: kempf%hplabsc@hplabs.HP.COM
cc: common-lisp-object-system@sail.stanford.edu
Message-ID: <870522-110443-2785@Xerox>
The ANSI 87-002 CLOS spec, pg. 2-6-2-7 states that rebinding of
argument parameters for CALL-NEXT-METHOD is not permitted,
Actually, what it says is:
"Neither argument defaulting, nor using setq, nor rebinding variables
with the same
names as parameters of the method affects the values call-next-method
passes to the
method it calls."
By which it means the following is legal:
(defmethod foo ((b boat) x y)
(let ((x (1+ x))
(y (1+ y)))
(call-next-method)))
But that the next method will be called with the original values of x
and y, not one plus those values.
The reason is that, in the process of implementing COOL, I have
found need to do this.
Having made the clarification above, I would ask: Have you found the
need to rebind the parameters of the method or alter the values passed
by call-next-method? I would guess the latter since that is whats
really interesting and the only thing you couldn't get around by
renaming variables.
We should probably work this out so that it is possible to pass
arguments to call-next-method. As I remember, the problems were
specifying what happens if you change the arguments passed in such a way
that the current method itself would no longer be applicable.
∂22-May-87 1635 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 22 May 87 16:35:04 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 22 MAY 87 16:10:34 PDT
Date: 22 May 87 16:10 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Object creation discussion (at last!)
In-reply-to: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>'s
message of Mon, 27 Apr 87 01:30 EDT
To: Moon@STONY-BROOK.SCRC.Symbolics.COM
cc: Common-Lisp-Object-System@sail.stanford.edu
Message-ID: <870522-161034-1060@Xerox>
This message talks only about the things that I think happen with
initargs in Moon's proposal. Most of what I am going to say is just a
re-interpretation of Moon's description of his proposal. In Moon's
proposal there are lots of different declarations which involve
initargs, I am trying to understand just what those declarations really
say.
It seems to me that there are 3 different kinds of primitive
declarations involving initargs.
1) DECLARATION of Legality
This is a statement that in a call to make-instance of this class
or a subclass of this class it is legal to provide this initarg.
This primitive declaration does not exist in isolation in in Moon's
proposal, more on that later.
2) SPECIFICATION of how to process certain kinds of initargs.
This is a statement telling the system how to process a particular
initarg. In Moon's proposal, initargs which set slots are one
example of SPECIFICATION. Using the :initarg slot-option tells the
system that when that initarg is supplied the associated slot
should be set to the initargs value.
Another, more subtle, example of SPECIFICATION is the &key keywords
in initialize-instance method lambda-lists. These specify that a
given parameter in the method body should be bound to the value of
the initarg.
3) DEFAULTING the value of an initarg.
This provides a default value for an initarg be it an initarg which
is DECLARED in this class or one which is DECLARED in a superclass
of this class.
Moon's proposal tends to fold one or more of these primtive declarations
together in other declarations. That is probably appropriate, and I
would expect that our final design will do so as well. I am making
these distinctions now so that we can have some more precise mechanism
for talking about the kinds of things that can be done with initargs.
In Moon's proposal:
:initarg slot-options combines DECLARATION and SPECIFICATION
&key in initialize-instance combines DECLARATION and SPECIFICATION
:default-initargs combines DECLARATION (and DEFAULTING I
think)
Now lets look for a minute at how initargs are processed at
make-instance time. This breakdown also helps justify the breakdown I
used above.
Note that this is a naive model of how they are processed. Any
implementation would optimize this.
1. defaulting
the initargs supplied in the call to make-instance are combined
with the inherited initarg default values to get the full set of initargs.
2. declaration checking (error checking)
the full set of initargs is error checked to make sure they are all
legal
3a. specification implementation for slot initargs
the initargs which specify slot values are used to set slot values,
(slots not set in this way are set from their initforms)
3b. specification implementation for other initargs
call initialize-instance with the instance and the initargs.
Let me re-iterate the point of this message. I am just trying to flesh
out the primitive language of statements about initargs which I think
underlies Moon's proposal. I am not necessarily suggesting that this
primitive language is appropriate for use in the system, it may be that
we will want to continue using combined declarations. But I think this
language can be used to describe Moon's proposal, my earlier proposal
and one that Danny has been working on. As such I think it might be
helpful to us in trying to talk about these proposals.
∂23-May-87 0414 kempf%hplabsc@hplabs.HP.COM Re: Arguments to CALL-NEXT-METHOD
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 23 May 87 04:13:58 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Fri, 22 May 87 14:22:05 pdt
Received: by hplabsc ; Fri, 22 May 87 14:18:53 pdt
Date: Fri, 22 May 87 14:18:53 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705222118.AA05249@hplabsc>
To: Gregor.pa@Xerox.COM, kempf%hplabsc@hplabs.HP.COM
Subject: Re: Arguments to CALL-NEXT-METHOD
Cc: common-lisp-object-system@sail.stanford.edu
The problem required altering the values passed by CALL-NEXT-METHOD.
Passing arguments which would make the current method not be applicable
is certainly a problem which would need some thought. Off the top
of my head, two solutions I could think of would be to only allow
parameters to be passed which are not specialized in the lambda
list of the method or simply signal an error if no method exists.
I don't think there is any way to make this work with method combination
either, since the :AROUND method depends on CALL-NEXT-METHOD, according
to 87-001, pg. 1-24.
Jim Kempf kempf@hplabs.hp.com
∂23-May-87 1622 Bobrow.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 23 May 87 16:22:40 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 23 MAY 87 16:22:03 PDT
Date: 23 May 87 16:21 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>'s message of Fri,
22 May 87 14:18:53 pdt
To: kempf%hplabsc@hplabs.HP.COM
cc: Gregor.pa@Xerox.COM, common-lisp-object-system@sail.stanford.edu
Message-ID: <870523-162203-1587@Xerox>
Passing arguments which would make the current method not be
applicable is certainly a problem which would need some thought.
Off the top of my head, two solutions I could think of would be to
only allow parameters to be passed which are not specialized in the
lambda list of the method or simply signal an error if no method
exists.
The model I prefer is that call-next-method arguments that are used for
method discrimination must have the SAME class as the supplied value.
This should be checked at run-time and an error signalled if not true.
If the compiler can PROVE that the new parameter will have the same
class then as an optimization the check may be skipped. Thus changing
some arguments, but passing down the input parameters which are not
special and have not been rebound fall in that category.
Of course, undiscriminated arguments can be changed freely.
∂23-May-87 1839 Bobrow.pa@Xerox.COM Object creation discussion (at last!)
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 23 May 87 18:39:20 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 23 MAY 87 18:35:30 PDT
Date: 23 May 87 18:35 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Object creation discussion (at last!)
To: Common-Lisp-Object-System@SAIL.STANFORD.EDU
cc: Bobrow.pa@Xerox.COM
Message-ID: <870523-183530-1635@Xerox>
The following is another proposal for instance allocation. Consider it
as a thought exercise to try to understand what might be possible. It
tries to provide the same functional capabilities as Moon's, but takes a
different point of view with respect to simplicity -- by trying to
adding the smallest number of new features . The messages by Moon and
Gregor have been most clarifying on these diffeent views of simplicity.
This proposal builds both their previous proposals, but is more in the
spirit of Gregor's. After the specification, I respond to issues that
have come up in previous messages.
The proposal
1) provides a specializable, error-checkable intermodule mechanism for
creating instances (make-instance).
2) divides the instance creation specification between internal and
interface parts (:initargs option). The external part specifies
allowable arguments to make-instance.
3) assumes optimization of specific calls to make-instance with quoted
arguments so that creating instances can be fast (see Gregor's recent
message), thus allowing removal of the :constructor option.
----
PROPOSAL:
The defclass class options no longer include a :constructor option.
The defclass class options are extended to include:
(:initargs (<initarg-name>
[:slotname <slot-specifier>]
[:default-value-form <form>])*)
Each <initarg-name> is a symbol specified to be a legal argument to
make-instance.
<initarg-name> is an abbreviation for (<initarg-name>).
:slotname <slot-specifier>
<slot-specifier> is <symbol> or (<symbol>*)
If <initarg-name> is used as a keyword argument to make-instance, then
the slot named <symbol> is initialized to the value provided for the
<initarg-name> argument. If <slot-specifier> is a list of <symbol>s,
then all those named slots are initialized with the same provided value.
An error is signalled for any <symbol> that does not name a slot of the
class.
:default-value-form <form>
If :default-value-form is provided, and if <initarg-name> is not
supplied explicitly in the call to make-instance, then the value of
<form> is used by make-instance as though it were provided. The
:default-value-form is evaluated in the lexical context of the defclass
form.
In the following, we say that an <initarg-name> has a "provided value"
if either
1) it is provided in the call to make-instance
2) the <initarg-name> has a :default-value-form
Multiple occurrences of <initarg-name>
If the same <initarg-name> appears more than once in the :initargs list,
it is equivalent to a single appearance of this symbol with the union of
the values of all the :slotname options, and the first (leftmost)
:default-value-form option.
Inheritance
The effective :initargs list for any class is the concatenation of lists
from all of the classes in its class-precedence-list in that order (most
to least specific). The multiple occurrence rule defines the behavior
for multiple occurrences of <initarg-name>.
Multiple occurrences of <slotname>
If more than one <initarg-name> is specified to initialize a particular
slot, then all of them CAN be used to initialize the slot. The leftmost
provided value (leftmost in the effective :initargs list) will be used
to initialize the slot.
Interaction with slot initforms
If an <initarg-name> has a provided value, then that provided value is
used to initialize the slot, else it is initialized as specified in the
slot :initform option.
EXAMPLES:
(defclass point ()
((x :initform 0)
(y :initform 0))
(:init-args
(:x :slotname x)
(:y :slotname y)
:rho
:theta)
The keywords :x, :y, :rho and :theta are legal arguments to
make-instance. Values provided for :x and :y initialize slots x and y
respectively. If there are no provided values, x and y are initialized
to 0.
(defclass picture (point)
(bitmap
saved-bitmap)
(:init-args
(:y :default-value-form *screen-top*)
(:image :slotname (bitmap saved-bitmap))))
:x, :y, :rho, :theta, and :image are legal arguments to make-instance. A
value provided for :image will initialize both slots bitmap and
saved-bitmap. If a call to make-instance does not specify a value for
:y, then the slot y will be initialized to *screen-top*, and
initialize-instance will see a provided value of *screen-top* for :y.
GENERIC FUNCTION INVOLVED IN OBJECT CREATION
MAKE-INSTANCE kind &rest init-plist
is a generic function that provides the external interface to object
creation. Methods exist for symbol and standard-class.
Method on SYMBOL
It finds the class of that name, and calls the generic-function on the
class. It signals an error if no such class is found.
Method on STANDARD-CLASS
This method checks the init-plist. It ensures that init-plist contains
only <initarg-name>s that are allowed by the class, else signals an
error. For each <initarg-name> that has a <default-value-form>, and
does not appear in the init-plist, it appends <initarg-name>
<value-of-form> to init-plist.
This method then calls allocate-instance with the class, and the
extended init-plist.
On the object returned from allocate-instance, this method first
initializes all slots that have an associated <initarg-name> and a
provided value, and then initializes the rest of the slots from their
slot-option :initform.
This method then calls initialize-instance on the object, and the
extended init-plist.
ALLOCATE-INSTANCE class &key &allow-other-keys.
returns a new uninitialized instance of the specified class.
INITIALIZE-INSTANCE instance &key &allow-other-keys
is the user's procedural handle on initialization. It uses
standard-method-combination. The primary method on standard-object just
returns the instance. One standard way of using initialize will be to
have :before methods, so that all these methods will be fired.
CLASS-INITARGS class &optional local-only
returns the initargs for a standard-class. setf works with
class-initargs when local-only is T.
----
ISSUES raised in messages:
1) Lexical proximity (ie why not have an :initarg slot option)
The criterion for simplicity used here is that there should be
exactly one way of specifying legal initargs-names. This simplifies
code for readers who minimize reading of documentation. Another
argument is that specifying initargs is part of the interface, not the
implementation, and hence does not belong with the slot.
I also believe that it is the environment's responsibility to provide
useful views of the class in addition to the text view in the file; for
example, allowing one to see the set of all slots in a class and all
their effective slot-options. Another such view should show the names
of initarg-names that can be used to initialize particular slots.
2) Can methods specify legal :initargs not in the class :initargs
option?
No, because the specification is part of the class definition. The
method is an implementation of part of the specification.
3) How should methods and initargs be kept in synch
Again I believe this is something that a good environment will help
with. No later than the time when the first instance is created, the
environment can warn the user about :initarg-names that are not used for
methods or slot initialization, and methods with illegal argument names.
4) Why get rid of constructors?
This again calls on the simplicity criterion of having only one way
to do something. Also, I found the rules for matching constructor
argument names with slotnames and initarg-names were very complicated
and confusing.
The two arguments for constructors were:
1) Optimized code can be written for the constructors. But Gregor
showed how this can be done for an equivalent set of calls to
make-instance with quoted arguments. These calls can even be compiled
in-line if desirable.
2) Constructors can initialize slots that have no external interface.
But so can user functions that call make-instance.
5) Why keep :initforms?
Gregor has suggested that we eliminate the slot :initform option. I
have not suggested this because I believe that :initforms are part of
the internal specification of the class, and :default-value-form is part
of the external specification.
6) Why is make-instance a generic function?
This allows the user to specialize make-instance for different
meta-classes, thus avoiding any of the initialization protocol. I could
also imagine using it for objects that I want to create only if I
couldn't find an existing object with the a given unique-identifier.
The only argument I remember against make-instance as a generic function
was that constructors didn't call make-instance, so it was the wrong
level to have a generic function. I take this to be an argument against
having constructors.
7) What about a more compact syntax?
Since there are only two options for an initarg-name, we could use
positional notation, with
(<initarg-name> <slot-specifier> <default-value-form>).
We could then use
(<initarg-name> <slot-specifier>)
if no <default-value-form> is to be given, and
(<initarg-name> NIL <default-value-form>)
if no <slot-specifier> is to be given, and
<initarg-name>
for no options.
8) Must the user specify &allow-other-keys and :before for
initialize-instance?
A simple macro can add the first or both of these.
I believe that this is another example where the standard should be
augmented by a STANDARD library of useful extensions endorsed by the
committee. Other things in that category for me are the macro for
defining simple-method-combination, and the standard simple
method-combination forms (and, or etc.). This is a fourth layer for the
standard.
∂25-May-87 0816 kempf%hplabsc@hplabs.HP.COM Re: Arguments to CALL-NEXT-METHOD
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 25 May 87 08:16:14 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Mon, 25 May 87 08:15:08 pdt
Received: by hplabsc ; Mon, 25 May 87 08:14:20 pdt
Date: Mon, 25 May 87 08:14:20 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705251514.AA22567@hplabsc>
To: Bobrow.pa@Xerox.COM, kempf%hplabsc@hplabs.HP.COM
Subject: Re: Arguments to CALL-NEXT-METHOD
Cc: Gregor.pa@Xerox.COM, common-lisp-object-system@sail.stanford.edu
>The model I prefer is that call-next-method arguments that are used for
>method discrimination must have the SAME class as the supplied value.
>This should be checked at run-time and an error signalled if not true.
>If the compiler can PROVE that the new parameter will have the same
>class then as an optimization the check may be skipped. Thus changing
>some arguments, but passing down the input parameters which are not
>special and have not been rebound fall in that category.
This would also be acceptable, and would provide even more flexibility,
since the writer of the subclass method would have the option of
passing another object of the same class as one of the specialized
arguments. The capability to alter arguments is typically required
when the writer of the subclass method wants to filter the arguments
before passing them to the superclass method.
Jim Kempf kempf@hplabs.hp.com
∂25-May-87 1754 masinter.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 25 May 87 17:54:10 PDT
Received: from Semillon.ms by ArpaGateway.ms ; 25 MAY 87 17:52:57 PDT
From: masinter.pa@Xerox.COM
Date: 25 May 87 17:52:36 PDT
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: kempf%hplabsc@hplabs.HP.COM's message of Mon, 25 May 87
08:14:20 pdt, <8705251514.AA22567@hplabsc>
To: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
cc: Bobrow.pa@Xerox.COM, Gregor.pa@Xerox.COM,
common-lisp-object-system@sail.stanford.edu
Message-ID: <870525-175257-2213@Xerox>
Does 3 have the same class as 3333333?
∂25-May-87 1818 Bobrow.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 25 May 87 18:18:38 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 25 MAY 87 18:15:42 PDT
Date: 25 May 87 18:15 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: masinter.pa's message of 25-May-87 17:52:36 PDT
To: masinter.pa@Xerox.COM
cc: kempf%hplabsc@hplabs.HP.COM, Bobrow.pa@Xerox.COM,
Gregor.pa@Xerox.COM, common-lisp-object-system@sail.stanford.edu
Message-ID: <870525-181542-2236@Xerox>
Does 3 have the same class as 3333333?
Yes. Subranges do not have classes. (e.g. fixnums)
danny
∂26-May-87 1724 Masinter.pa@Xerox.COM Re: CLOS vs. subtypes of FLOAT
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 26 May 87 17:24:17 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 26 MAY 87 15:56:56 PDT
Date: 26 May 87 15:47 PDT
From: Masinter.pa@Xerox.COM
Subject: Re: CLOS vs. subtypes of FLOAT
In-reply-to: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>'s
message of Thu, 21 May 87 16:37 EDT
To: Moon@STONY-BROOK.SCRC.Symbolics.COM
cc: Common-Lisp-Object-System@SAIL.Stanford.Edu
Message-ID: <870526-155656-1011@Xerox>
>From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: CLOS vs. subtypes of FLOAT
...
>Unfortunately this elegant-sounding choice can't be taken without
>changing Common Lisp incompatibly. The problem is that Common Lisp
>specifies (CLtL p.19) that in an implementation without short-floats,
>(typep x 'short-float) does the same thing as (typep x 'single-float),
>rather than always returning nil. We want to keep typep consistent
>with class-instance relationships, to avoid giving Common Lisp too
>subtly-incompatible type systems.
The conclusion I've reached is that there is no good way to allow
discrimination on subtypes of FLOAT without changing Common Lisp, or at
least the required subtypes of FLOAT.
I'd vote for adopting Pavel's proposal NONE with the footnote that a
cleanup in the area of floating point classes is required., because the
current floating point types are not sufficiently well specified to
allow any useful discrimination on them.
∂26-May-87 2253 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Arguments to CALL-NEXT-METHOD
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 26 May 87 22:53:13 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 152832; Wed 27-May-87 01:52:38 EDT
Date: Wed, 27 May 87 01:52 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: Arguments to CALL-NEXT-METHOD
To: common-lisp-object-system@sail.stanford.edu
In-Reply-To: <870523-162203-1587@Xerox>
Message-ID: <870527015250.2.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 23 May 87 16:21 PDT
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Passing arguments which would make the current method not be
applicable is certainly a problem which would need some thought.
The model I prefer is that call-next-method arguments that are used for
method discrimination must have the SAME class as the supplied value.
This should be checked at run-time and an error signalled if not true.
If the compiler can PROVE that the new parameter will have the same
class then as an optimization the check may be skipped. Thus changing
some arguments, but passing down the input parameters which are not
special and have not been rebound fall in that category.
Of course, undiscriminated arguments can be changed freely.
This sounds good. There are two problems I remember from the last time
we discussed this. One is that testing the class isn't good enough since
we have method selection by eql as well as by typep. I guess all this
means is that the -only- way the compiler can prove that the run-time
test isn't needed is when you pass exactly the input parameter; but that
is the important special case.
The other problem is that the issue is not passing arguments which would
make the -current- method not be applicable, so much as passing
arguments which would change which -other- methods are applicable. This
is particularly easy to see in an implementation model where the generic
function first finds all the applicable methods and sets them up for
call-next-method, and then calls the first method, and call-next-method
just pulls methods off that list. Because of this problem, you can't do
anything at compile time because you don't know which parameters of the
generic function are used for method selection; they might be more than
just the specialized parameters of the current method. They might change
long after the current method is compiled, by defining a new method
that specializes a different parameter.
Does anyone think we couldn't get away with this rule, which I think is
the most restrictive possible, short of not being able to change the
arguments at all (as in 87-002): Call a parameter of the generic
function "discriminating" if -any- method for that generic function
specializes the parameter. Each argument to call-next-method that
corresponds to a discriminating parameter of the generic function must
be EQL to the argument supplied to the generic function or an error is
signalled. The other arguments to call-next-method can be changed
freely. Optimizations of the error checking are possible but they
should be invisible to the programmer.
Less restrictive rules are possible but all I could think of
either were much more complicated to explain, or admitted bugs, or both.
∂26-May-87 2259 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Object creation discussion (at last!)
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 26 May 87 22:59:38 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 152858; Wed 27-May-87 01:59:04 EDT
Date: Wed, 27 May 87 01:59 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: Object creation discussion (at last!)
To: Common-Lisp-Object-System@sail.stanford.edu
In-Reply-To: <870522-161034-1060@Xerox>
Message-ID: <870527015917.3.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 22 May 87 16:10 PDT
From: Gregor.pa@Xerox.COM
This message talks only about the things that I think happen with
initargs in Moon's proposal. Most of what I am going to say is just a
re-interpretation of Moon's description of his proposal. In Moon's
proposal there are lots of different declarations which involve
initargs, I am trying to understand just what those declarations really
say.
It seems to me that there are 3 different kinds of primitive
declarations involving initargs.
1) DECLARATION of Legality
This is a statement that in a call to make-instance of this class
or a subclass of this class it is legal to provide this initarg.
This primitive declaration does not exist in isolation in in Moon's
proposal, more on that later.
2) SPECIFICATION of how to process certain kinds of initargs.
This is a statement telling the system how to process a particular
initarg. In Moon's proposal, initargs which set slots are one
example of SPECIFICATION. Using the :initarg slot-option tells the
system that when that initarg is supplied the associated slot
should be set to the initargs value.
Another, more subtle, example of SPECIFICATION is the &key keywords
in initialize-instance method lambda-lists. These specify that a
given parameter in the method body should be bound to the value of
the initarg.
3) DEFAULTING the value of an initarg.
This provides a default value for an initarg be it an initarg which
is DECLARED in this class or one which is DECLARED in a superclass
of this class.
I agree with this analysis.
Moon's proposal tends to fold one or more of these primtive declarations
together in other declarations.
Forbidding DECLARATION independently of SPECIFICATION was intended to be
a FEATURE of what I proposed. That is, the specifications and the
declarations were supposed to be kept consistent automatically by not
having a syntax that could make them inconsistent.
That is probably appropriate, and I
would expect that our final design will do so as well. I am making
these distinctions now so that we can have some more precise mechanism
for talking about the kinds of things that can be done with initargs.
I agree that this is a good way to proceed.
In Moon's proposal:
:initarg slot-options combines DECLARATION and SPECIFICATION
&key in initialize-instance combines DECLARATION and SPECIFICATION
Agreed.
:default-initargs combines DECLARATION (and DEFAULTING I
think)
No, that's a persistent misunderstanding (my "at last" writeup was not
very clear on this). :default-initargs does DEFAULTING only.
Now lets look for a minute at how initargs are processed at
make-instance time. This breakdown also helps justify the breakdown I
used above.
Note that this is a naive model of how they are processed. Any
implementation would optimize this.
1. defaulting
the initargs supplied in the call to make-instance are combined
with the
inherited initarg default values to get the full set of initargs.
2. declaration checking (error checking)
the full set of initargs is error checked to make sure they are all
legal
3a. specification implementation for slot initargs
the initargs which specify slot values are used to set slot values,
(slots not set in this way are set from their initforms)
3b. specification implementation for other initargs
call initialize-instance with the instance and the initargs.
I agree with this.
Let me re-iterate the point of this message. I am just trying to flesh
out the primitive language of statements about initargs which I think
underlies Moon's proposal. I am not necessarily suggesting that this
primitive language is appropriate for use in the system, it may be that
we will want to continue using combined declarations. But I think this
language can be used to describe Moon's proposal, my earlier proposal
and one that Danny has been working on. As such I think it might be
helpful to us in trying to talk about these proposals.
Thanks, this is a good framework for focussing the discussion.
∂26-May-87 2335 kempf%hplabsc@hplabs.HP.COM Re: CLOS vs. subtypes of FLOAT
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 26 May 87 23:35:06 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Tue, 26 May 87 21:00:10 pdt
Received: by hplabsc ; Tue, 26 May 87 20:59:25 pdt
Date: Tue, 26 May 87 20:59:25 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705270359.AA00431@hplabsc>
To: Masinter.pa@Xerox.COM, Moon@STONY-BROOK.SCRC.Symbolics.COM
Subject: Re: CLOS vs. subtypes of FLOAT
Cc: Common-Lisp-Object-System@SAIL.Stanford.Edu
I agree on adopting the NONE proposal, with cleanup on float subtyping.
∂27-May-87 0803 Bobrow.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 27 May 87 08:03:04 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 27 MAY 87 08:00:39 PDT
Date: 27 May 87 08:00 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>'s
message of Wed, 27 May 87 01:52 EDT
To: Moon@STONY-BROOK.SCRC.Symbolics.COM
cc: common-lisp-object-system@sail.stanford.edu
Message-ID: <870527-080039-1739@Xerox>
Call a parameter of the generic function "discriminating" if
-any- method for that generic function specializes the parameter.
Each argument to call-next-method that corresponds to a
discriminating parameter of the generic function must be EQL to the
argument supplied to the generic function or an error is signalled.
The other arguments to call-next-method can be changed freely.
Optimizations of the error checking are possible but they should be
invisible to the programmer.
You are correct that we must consider all arguments that could be
discriminating.
The appropriate rule is
*The set of methods applicable to a changed set of arguments for
call-next-method must be the same as set of applicable methods for the
original arguments to the method". There are various compilations of
this rule.
Call any parameter of the generic function that is discriminated on an
individual an "individual discriminated parameter" and the others "class
discriminated parameters". Then the rule is that one cannot change the
class (even the implementation dependent class) of a class discriminated
argument, nor the identity (EQL) of an individual discriminated
argument.
Here is an example where one wants to change the value of a class
discriminated parameter. A gauge is a display device. Assume
different behaviors for integers and floating point input to the gauge.
(defmethod display-value ((g gauge)(i integer))
(move-display-to-position g i)) ;; show value whatever
it is
(defclass bounded-gauge (gauge)
((max-reading :initform 100)))
(defmethod display-value ((g bounded-gauge) (i integer))
(with-slots (g)
(call-next-method g (min i max-reading))))
∂27-May-87 1057 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Arguments to CALL-NEXT-METHOD
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 27 May 87 10:56:49 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 153591; Wed 27-May-87 13:49:35 EDT
Date: Wed, 27 May 87 13:49 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: Arguments to CALL-NEXT-METHOD
To: common-lisp-object-system@sail.stanford.edu
In-Reply-To: <870527-080039-1739@Xerox>
Message-ID: <870527134949.5.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 27 May 87 08:00 PDT
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
The appropriate rule is
The set of methods applicable to a changed set of arguments for
call-next-method must be the same as the set of applicable methods for the
original arguments to the method".
Okay, I'll buy that.
Here is an example where one wants to change the value of a class
discriminated parameter. A gauge is a display device....
It's a somewhat contrived example, but I get your point.
Shall we call this a decision and record it someplace?
∂27-May-87 1122 RPG OOPSLA Lisp and Object-Oriented Programming Workshop
To: common-lisp-object-system@SAIL.STANFORD.EDU
There will be a workshop on Lisp and Object-Oriented Programming on Monday
October 5 from 9am until noon at OOPSLA. The Common Lisp Object System
(CLOS) will be the highlight of the workshop, with presentations about
CLOS by the designers along with critiques, analyses, and responses to the
Object System, the latter selected based on contributed position papers.
Attendance will be limited to people who know Lisp and are familiar with
existing object-oriented languages.
If you would like to attend, please send me a 1-2 page description of your
position regarding either the Common Lisp Object System or
Lisp/object-oriented programming before August 1; netmail is acceptable.
Invitations will be sent on September 1. Attendance is limited to 35
people.
Richard P. Gabriel
Lucid, Inc
707 Laurel Street
Menlo Park, CA 94025
(415)329-8400
rpg@sail.stanford.edu
∂27-May-87 1124 RPG Floats
To: common-lisp-object-system@SAIL.STANFORD.EDU
Pavel's note provides a good analysis, but we should take it further. I
think there are a number of issues at work here: 1. Common Lisp makes it
difficult or impossible to put forward a sensible definition of the class
structure of floats even when only one implementation is considered; 2. a
class structure that parallels the type structure of floats is not useful
to solve the problem of portability of CLOS code among implementations; 3.
CLOS does not provide the sort of expressive machinery to solve these
problems even if we drop the requirement of making the class structure
parallel the type structure.
Let us suppose that if a programmer writes
(defmethod foo ((x single-float))...)
(defmethod foo ((x double-float))...)
he intends that the first method will be used when the internal
representation of the argument to FOO has some limited precision and that
the second method will be used when there is more precision. As Pavel
points out, different programs or even algorithms will be used depending
on the precision of floats available. I will ignore the case that the
programmer is trying to tell the compiler how to improve the code.
In addition, the programmer is providing additional documentation
of his code by defining the methods like this - the reader knows
that the two methods are carefully chosen to behave well for certain
precisions of floating point.
Issue 1:
I will present a scenario for a valid (and sensible) Lisp implementation
situation in which the implied class structure tends to be nonsensical
because the Common Lisp type system is slightly nonsensical.
Today, there are computers that have only double-precision floating point
hardware. These vendors often support languages in which variables can be
declared of type SINGLE-FLOAT (in effect), but these languages produce
code that loads the floating point hardware with the values of such
variables by coercing to doubles, operates on them, and then unloads
to the variables, coercing to SINGLE-FLOATs on the way. People who have
code that is already declared with SINGLE-FLOATs are happy to suffer only
a 10%-20% slowdown over what they would get if they changed their code to
declare DOUBLE-FLOATs.
A Common Lisp for this machine, then, might use only a double-precision
representation throughout. But, according to pages 18-19 of CLtL, this
type would be considered SINGLE-FLOAT, though the types SHORT-FLOAT,
DOUBLE-FLOAT, and LONG-FLOAT are synonymous with it as far as TYPEP is
concerned. FORMAT will consider all floating point numbers to be singles
and output accordingly.
The result is that the programmer who writes FOO as above would not have
an implementation that distinguishes between SINGLE-FLOAT and
DOUBLE-FLOAT. In his implementation, there is only one floating point
representation, and to write a method that invokes the double-precision
code he could write the single method as one of:
1. (defmethod foo ((x float))...)
2. (defmethod foo ((x single-float))...)
3. (defmethod foo ((x double-float))...)
The first and second of these are possibilities under Pavel's SOME
proposal, while the third is a possibility under Pavel's ALL proposal.
The first of these would work because there is only one subclass of FLOAT,
namely SINGLE-FLOAT, and therefore FLOAT and SINGLE-FLOAT are synonymous.
The second of these works because double-precision numbers are of class
(and type) SINGLE-FLOAT. The third of these works if CLASS-OF is allowed
to return DOUBLE-FLOAT or if the class SINGLE-FLOAT is a subclass of
DOUBLE-FLOAT. CLtL doesn't state what TYPE-OF should return, but it seems
to make sense for it to return SINGLE-FLOAT to help FORMAT do its thing.
The first of these alternatives fails to provide the best documentation,
because it seems to be a method defined for a general class of floats,
from SHORT-FLOATs to LONG-FLOATs. The second one is misleading. The third
of these alternatives possibly forces us into an inconsistency with the
Common Lisp type structure.
None of these alternatives is satisfying. This argues that CLtL
incorrectly outlines the acceptable type structures for floats.
Basing a rational class structure on an irrational type structure
seems inadvisable.
Issue 2:
Suppose we have two Common Lisp implementations, each with all of the
possible subtypes of FLOAT as distinct types with distinct representations.
Suppose further that the first implementation is on an S3 where a
SHORT-FLOAT is an immediate type with 32 bits of mantissa, a SINGLE-FLOAT
is a boxed type with 64 bits of mantissa, a DOUBLE-FLOAT is a boxed type
with 128 bits of mantissa, and a LONG-FLOAT is a boxed type with
256 bits of mantissa.
Suppose the second implementation is on a 68020 with special floating-point
hardware where a SHORT-FLOAT is an immediate type with 22 bits of mantissa,
SINGLE-FLOATs are boxed with 28 bits of mantissa, DOUBLE-FLOATs are boxed
with 56 bits of mantissa, and LONG-FLOATS are boxed with 80 bits of mantissa.
Now suppose that the programmer for the second machine has 4 methods,
one for each type of float where each method performs a different
computation based on the convergence properties of each floating point
type. When he tries to port his code to the first machine, the methods
get mapped to the four classes, but his programs are wrong! His SHORT-FLOAT
method is obsolete, the next three shift down one, and he has to think about
a LONG-FLOAT version for the expanded precision.
That is, the names of the types match, but the underlying descriptions of
of the representations do not.
The point is that the proposal to parallel the Common Lisp type structure
with a class structure is based on the belief that programmers want to tailor
code to the floating point formats available on a machine, but the fact
is that programmers who write such code wish to have their methods chosen
on the basis of a description of the floating point precisions and not on some
set of names of floating point types.
As Steele himself points out, there is no guaranteed portability of floating
point code in Common Lisp, and the type breakdown is only a means of providing
an aid for transportation.
Issue 3:
The crux of the matter is the the Common Lisp type system provides an
abstract type system down to some level of specificity, at which point
the type system begins to refer to internal machine-dependent representations.
We see the same problem with floats that exists with fixnums: these types
refer to machine-dependent representations.
One solution to the problem would be to define something like parametric
classes. Instead of writing
(defmethod foo ((x single-float))...)
we would write
(defmethod foo ((x (float 24 56))...)
which would state that x ought to be a floating point number whose
representation has between 24 and 56 bits of mantissa. This solution is
workable to some extent if we limit the paramaters to constants and *,
because there is presumably a mapping between (float x y) and one of the
floating-point type names at defmethod time - the mapping is made upon
``transportation.''
We could make the same argument about fixnums:
(defmethod baz ((x (fixnum 10 *)))...)
indicates that this method ought to be invoked when given a fixed precision
number whose representation has at least 10 bits of information.
When we argue that a programmer wishes to write code that discriminates on
the subtypes of FLOAT, we really argue that he wishes to parameterize his
code based on representation. The CLOS class hierarchy is applicable to
purely abstract types and not to representational types. To say this
again in a different way, there is no descriptive power in a pure name,
and in the case of floating point numbers, we wish to map a description to
a class name and then discriminate.
One can argue that this points out an inherent limitation of CLOS - that
it operates in the abstract type domain rather than in the
representational domain. In its pristine form, instances in CLOS are dull
DEFSTRUCT-like objects, and many of the aspects of pristine CLOS as well
as the meta-object protocol are based on optimizing the results of this
choice of what instances are.
It therefore only makes sense that when CLOS comes up on a situation where
representational issues dominate that it is found weak.
Selecting the NONE option doesn't solve any problems, it only admits
defeat.
-rpg-
∂27-May-87 1331 Masinter.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 27 May 87 13:30:46 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 27 MAY 87 11:09:42 PDT
Date: 27 May 87 11:08 PDT
From: Masinter.pa@Xerox.COM
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>'s
message of Wed, 27 May 87 13:49 EDT
To: common-lisp-object-system@sail.stanford.edu
Message-ID: <870527-110942-1982@Xerox>
I'm vaguely uneasy about allowing any argument reassignment in
call-next-method; normally lexical variables without any external
reference are insensitive to rebinding them to themselves, e.g.,
(lambda (a b c) ... code ...)
is equivalent to
(lambda (a b c) (let ((a a) (b b) (c c)) ... code ...))
The only precondition for this transformation is that there is no
reference to the variables outside of the scope of the rebinding.
When call-next-method pays attention to reassignment, I presume that it
is only reassignment of the original lexical variables (am I wrong?)
(defmethod frob ((a widget) b c)
.. (setq a (make-widget ...))
...
(call-next-method) ...))
that this would not be the same as
(defmethod frob ((a widget) b c)
(let ((a a))
.. (setq a (make-widget ...))
...
(call-next-method) ...)))
right?
∂27-May-87 1604 Gregor.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 27 May 87 16:04:30 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 27 MAY 87 14:04:08 PDT
Date: 27 May 87 14:03 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: Masinter.pa's message of 27 May 87 11:08 PDT
To: Masinter.pa@Xerox.COM
cc: common-lisp-object-system@sail.stanford.edu
Message-ID: <870527-140408-2308@Xerox>
I don't believe we are saying that rebinding or changing the value of a
binding would affect call-next-method. Rather, I think we are talking
about another form of call-next-method which would allow arguments to be
passed to it explicitly.
∂27-May-87 1604 Bobrow.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 27 May 87 16:04:37 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 27 MAY 87 14:08:28 PDT
Date: 27 May 87 14:08 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: Masinter.pa's message of 27 May 87 11:08 PDT
To: Masinter.pa@Xerox.COM
cc: common-lisp-object-system@sail.stanford.edu
Message-ID: <870527-140828-2315@Xerox>
I was proposing that call-next-method be given arguments
(defmethod frob ((a widget) (b integer) c)
...
(call-next-method a (sub1 b) c) ...))
where the values given to call-next-method are checked against the
original bindings of the parameters. (call-next-method) uses the
original parameters, and is insensitive to rebindings.
So (defmethod frob ((a widget) b c)
.. (setq a (make-widget ...))
...
(call-next-method) ...))
should be the same as
(defmethod frob ((a widget) b c)
(let ((a a))
.. (setq a (make-widget ...))
...
(call-next-method) ...)))
∂27-May-87 1605 Gregor.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 27 May 87 16:05:20 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 27 MAY 87 15:35:16 PDT
Date: 27 May 87 15:35 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>'s
message of Wed, 27 May 87 13:49 EDT
To: Moon@STONY-BROOK.SCRC.Symbolics.COM
To: Bobrow.pa@Xerox.COM
cc: common-lisp-object-system@sail.stanford.edu
Message-ID: <870527-153516-2470@Xerox>
It seems to me that the whole notion of a 'class discriminated
parameter' is a little problematic. After all, any parameter which is
not an 'individual discriminated parameter' is class discriminated; the
default discrimination of an argument is T. This is not a mute point
since there is no rule that says that someone can't make a class which
has no supers at all (hence an entire different root node).
Also it seems that Danny's example is an excellent example of why we
can't compile the rule that you can't change the applicable set of
methods down into the compilations he gives.
Specifically, Danny's "Assume different behaviors for integer and
floating point input to the gauge" finesses too important a point.
If you had a gauge which just had a method like this:
(defmethod display-value ((g gauge) v)
... show the value ...)
You would want to implement the bounded gauge method like this:
(defmethod display-value ((g bounded-gauge) v)
(with-slots (g)
(call-next-method g (min v max-reading))))
You wouldn't want to have to say:
(defmethod display-value ((g bounded-gauge) v)
(with-slots (g)
(call-next-method g (number-coerce v (min v max-reading)))))
The point is that while the first method on bounded gauge might change
the class of the argument (it could change 151.23 to 100) it wouldn't
change the set of applicable methods. I think this shows why the stated
rule must be:
"The set of methods applicable to a changed set of arguments for
call-next-method must be the same as set of applicable methods for
the
original arguments to the method"
Not any of the proposed compilations of that rule.
Also, we will presumably want APPLY-NEXT-METHOD in addition to
call-next-method.
∂27-May-87 1753 Moon@SAPSUCKER.SCRC.Symbolics.COM Re: Arguments to CALL-NEXT-METHOD
Received: from [192.10.41.223] by SAIL.STANFORD.EDU with TCP; 27 May 87 17:53:09 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by SAPSUCKER.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 133080; Wed 27-May-87 20:37:44 EDT
Date: Wed, 27 May 87 20:37 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: Arguments to CALL-NEXT-METHOD
To: common-lisp-object-system@sail.stanford.edu
In-Reply-To: <870527-153516-2470@Xerox>
Message-ID: <870527203752.7.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 27 May 87 15:35 PDT
From: Gregor.pa@Xerox.COM
Also, we will presumably want APPLY-NEXT-METHOD in addition to
call-next-method.
No, we changed call-next-method from a macro to lexically local function
so that you could just say (apply #'call-next-method ...).
∂27-May-87 1909 kahn.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 27 May 87 19:09:51 PDT
Received: from Salvador.ms by ArpaGateway.ms ; 27 MAY 87 16:18:36 PDT
Date: Wed, 27 May 87 16:18:15 PDT
From: Ken Kahn <Kahn.pa@Xerox.COM>
Subject: Re: Arguments to CALL-NEXT-METHOD
In-Reply-To: <870527-153516-2470@Xerox>
To: Gregor.pa@Xerox.COM
cc: Moon@STONY-BROOK.SCRC.Symbolics.COM, Bobrow.pa@Xerox.COM,
common-lisp-object-system@sail.stanford.edu
Message-ID: <870527-161836-2566@Xerox>
> After all, any parameter which is not an 'individual discriminated
parameter'
> is class discriminated; the default discrimination of an argument is
> T. This is not a mute point since there is no rule that says that
someone
> can't make a class which has no supers at all (hence an entire
different
> root node).
Does this mean that PCL is incorrect in its implementation of method
lookup when some of the arguments are specified as instances of T? The
point is that allowing for another root node can be very expensive.
References
Gregor's message of Wed, 27 May 87 15:35:00 PDT -- Re: Arguments to
CALL-NEXT-METHOD
∂27-May-87 1910 Gregor.pa@Xerox.COM OK, I stand corrected
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 27 May 87 19:10:18 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 27 MAY 87 18:08:33 PDT
Date: 27 May 87 18:08 PDT
From: Gregor.pa@Xerox.COM
Subject: OK, I stand corrected
To: Common-Lisp-Object-System@Sail.Stanford.edu
Message-ID: <870527-180833-2712@Xerox>
For the next 3 days, you will find me in my office, writing the
following on my whiteboard 1000 times.
moot n. 1. An ancient English meeting, especially a representative
meeting of the freemen of a shire. 2. An imaginary case argued by law
students as an exercise. --tr.v. mooted, mooting, moots. 1. a. To offer
as a subject for debate; bring up for discussion. b. To discuss or
debate. 2. To plead or argue (a case) in a moot court. --adj. 1.
Subject to debate; arguable; unresolved: a moot question. 2. Law.
Without legal significance, through having been previously decided or
settled; of only academic importance. [Middle English mot, moot, Old
English mot, moot, assembly. See mod- in Appendix.]
mute adj. muter, mutest. 1. Refraining from producing speech or vocal
sound. 2. a. Unable to speak. b. Unable to vocalize, as certain animals.
3. Law. Refusing, as a defendant, to plead either guilty or not guilty
when under arraignment. Used chiefly in the phrase stand mute. 4.
Phonetics. a. Not pronounced; silent, as the e in house. b. Pronounced
with a temporary stoppage of breath, as the sounds of p and b; plosive;
stopped. --See Synonyms at dumb. --n. 1. A person incapable of speech;
especially, one both deaf and mute. 2. Law. A defendant who refuses to
plead either guilty or not guilty when under arraignment. 3. Music. Any
of various devices used to muffle or soften the tone of a musical
instrument. 4. Phonetics. a. A silent or unpronounced letter. b. A
plosive; a stop. --tr.v. muted, muting, mutes. 1. To muffle or soften
the sound of. 2. To soften the tone, color, shade, or hue of. [Middle
English muet, from Old French, diminutive of mu, mute, from Latin mutus,
silent, dumb. See mu- in Appendix.] --mute"ly adv. --mute"ness n.
dyslexics of america
untie!
∂27-May-87 1910 Bobrow.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 27 May 87 19:10:28 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 27 MAY 87 18:11:37 PDT
Date: 27 May 87 18:11 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: Gregor.pa's message of 27 May 87 15:35 PDT
To: Gregor.pa@Xerox.COM
cc: Moon@STONY-BROOK.SCRC.Symbolics.COM, Bobrow.pa@Xerox.COM,
common-lisp-object-system@sail.stanford.edu
Message-ID: <870527-181137-2717@Xerox>
I think this shows why the stated rule must be:
"The set of methods applicable to a changed set of
arguments for call-next-method must be the same as set of
applicable methods for the original arguments to the method"
Not any of the proposed compilations of that rule.
I will revise my deinition slightly to try to save my proposed
compilation.
Any parameter that is specialized by any class other than T, and is not
specialized by an individual is "class discriminated". For any of those
arguments, not changing the class is sufficient to ensure that the set
of applicable methods is not changed.
For my example, in which there was specialization on the class of v was
done, it is necessary to write:
(defmethod display-value ((g bounded-gauge) v)
(with-slots (g)
(call-next-method g (number-coerce v (min v max-reading)))))
∂27-May-87 1910 Gregor.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 27 May 87 19:09:57 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 27 MAY 87 16:24:04 PDT
Date: 27 May 87 16:23 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: Ken Kahn <Kahn.pa>'s message of Wed, 27 May 87 16:18:15 PDT
To: Kahn.pa@Xerox.COM
cc: Gregor.pa@Xerox.COM, Moon@STONY-BROOK.SCRC.Symbolics.COM,
Bobrow.pa@Xerox.COM, common-lisp-object-system@sail.stanford.edu
Message-ID: <870527-162404-2575@Xerox>
Date: Wed, 27 May 87 16:18:15 PDT
From: Ken Kahn <Kahn.pa>
Does this mean that PCL is incorrect in its implementation of
method lookup when some of the arguments are specified as instances
of T? The point is that allowing for another root node can be very
expensive.
Uh, sorry. Right, confusion and stuff.
The rest of my message still applies. Namely, I think we have to make
the rule that you can't change the set of applicable methods.
∂28-May-87 0413 kempf%hplabsc@hplabs.HP.COM Re: Arguments to CALL-NEXT-METHOD
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 28 May 87 04:13:05 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Wed, 27 May 87 19:10:12 pdt
Received: by hplabsc ; Wed, 27 May 87 18:54:40 pdt
Date: Wed, 27 May 87 18:54:40 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705280154.AA13174@hplabsc>
To: Moon@STONY-BROOK.SCRC.Symbolics.COM,
common-lisp-object-system@sail.stanford.edu
Subject: Re: Arguments to CALL-NEXT-METHOD
This sounds good. I second the motion to call it a decision.
jak
∂28-May-87 0804 kempf%hplabsc@hplabs.HP.COM Re: Arguments to CALL-NEXT-METHOD
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 28 May 87 08:03:52 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 28 May 87 08:03:44 pdt
Received: by hplabsc ; Thu, 28 May 87 08:02:57 pdt
Date: Thu, 28 May 87 08:02:57 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705281502.AA19075@hplabsc>
To: Masinter.pa@Xerox.COM, common-lisp-object-system@sail.stanford.edu
Subject: Re: Arguments to CALL-NEXT-METHOD
>I'm vaguely uneasy about allowing any argument reassignment in
>call-next-method; normally lexical variables without any external
>reference are insensitive to rebinding them to themselves, e.g.,
>
My understanding was that rebinding would not be allowed, but
that passing of arguments would. Thus:
(defmethod frob ((a widget) b c)
(call-next-method (make-widget ...) b c)
)
This would make the arguments explicit, rather than relying on
binding.
jak
∂28-May-87 0856 kempf%hplabsc@hplabs.HP.COM Re: Floats
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 28 May 87 08:56:12 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 28 May 87 08:55:34 pdt
Received: by hplabsc ; Thu, 28 May 87 08:54:39 pdt
Date: Thu, 28 May 87 08:54:39 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705281554.AA19596@hplabsc>
To: RPG@SAIL.STANFORD.EDU, common-lisp-object-system@SAIL.STANFORD.EDU
Subject: Re: Floats
>One solution to the problem would be to define something like parametric
>classes. Instead of writing
>
>(defmethod foo ((x single-float))...)
>
>we would write
>
>(defmethod foo ((x (float 24 56))...)
>
>which would state that x ought to be a floating point number whose
>representation has between 24 and 56 bits of mantissa. This solution is
>workable to some extent if we limit the paramaters to constants and *,
>because there is presumably a mapping between (float x y) and one of the
>floating-point type names at defmethod time - the mapping is made upon
>``transportation.''
Or, alternatively, provide some means to extend STANDARD-TYPE-CLASS
for particular implementations of CLOS so that programmers could
write:
(defmethod foo ((x float-with-24-56-bits-mantissa) ...)
The extension could be done by implementors of CLOS for particular
hardware, and information on it could be provided through the
*FEATURES* flag (CLtL, pg. 448) so it could be used in readtime
conditionals, if necessary.
With regard to paramatetric classes, I think this is opening up
a whole new can of worms, which we may want to think seriously
about opening at this stage of the game. Languages like Eiffel
and (via generic packages) Ada have them, and there is no reason
that they couldn't be added to Common Lisp, but I would be reluctant
to write that into the standard, until the issues are better understood.
In particular, the interaction between multiple inheritance and
parameterized classes could potentially be quite complex.
>We could make the same argument about fixnums:
>
>(defmethod baz ((x (fixnum 10 *)))...)
>
>indicates that this method ought to be invoked when given a fixed precision
>number whose representation has at least 10 bits of information.
True.
>One can argue that this points out an inherent limitation of CLOS - that
>it operates in the abstract type domain rather than in the
>representational domain. In its pristine form, instances in CLOS are dull
>DEFSTRUCT-like objects, and many of the aspects of pristine CLOS as well
>as the meta-object protocol are based on optimizing the results of this
>choice of what instances are.
The instance creation protocol which is currently being discussed
actually deals with this issue. To a certain extent, the metaobject
protocol is the place for representation to be handled (in my opinion).
STANDARD-TYPE-CLASS is an example of a metaclass with a different
representation than STANDARD-CLASS, as is STANDARD-STRUCTURE-CLASS.
I could imagine a STANDARD-PERSISTENT-CLASS, which has instances
in a database or in the file system, or STANDARD-CD-ROM-CLASS, with
instances which are CD-ROM video or audio images.
>Selecting the NONE option doesn't solve any problems, it only admits
>defeat.
Well, I wouldn't put it that way. I think Larry's comment was appropriate.
The problem is not so much with CLOS as with how the Common Lisp type
system was put together (as was mentioned earlier in this note).
In my opinion, that should be where the problem is fixed.
jak
∂28-May-87 1158 Masinter.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 28 May 87 11:58:01 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 28 MAY 87 11:31:40 PDT
Date: 28 May 87 11:30 PDT
From: Masinter.pa@Xerox.COM
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>'s message of Thu,
28 May 87 08:02:57 pdt
To: common-lisp-object-system@sail.stanford.edu
Message-ID: <870528-113140-3619@Xerox>
I am embarrased that I totally misunderstood the call-next-method
proposal.
What does (call-next-method) do with optional arguments which have been
defaulted? Does it pass down the values as defaulted or does it
re-default them?
What about optionals which are left out of call-next-method?
∂28-May-87 1251 kempf%hplabsc@hplabs.HP.COM Re: Arguments to CALL-NEXT-METHOD
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 28 May 87 12:51:12 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 28 May 87 12:49:46 pdt
Received: by hplabsc ; Thu, 28 May 87 12:33:11 pdt
Date: Thu, 28 May 87 12:33:11 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705281933.AA21877@hplabsc>
To: Masinter.pa@Xerox.COM, common-lisp-object-system@sail.stanford.edu
Subject: Re: Arguments to CALL-NEXT-METHOD
>What does (call-next-method) do with optional arguments which have been
>defaulted? Does it pass down the values as defaulted or does it
>re-default them?
Good question. Off the top of my head, I'd suggest redefaulting. Any
objections?
>What about optionals which are left out of call-next-method?
Again, I'd assume they default. The model is that CALL-NEXT-METHOD
acts like FUNCALL or APPLY of the method, except method lookup is
short-circuited so the next applicable method is used. At least,
that's how I've been looking at it.
jak
∂28-May-87 1458 Bobrow.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 28 May 87 14:58:25 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 28 MAY 87 14:56:56 PDT
Date: 28 May 87 14:56 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>'s message of Thu,
28 May 87 12:33:11 pdt
To: kempf%hplabsc@hplabs.HP.COM
cc: Masinter.pa@Xerox.COM, common-lisp-object-system@sail.stanford.edu
Message-ID: <870528-145656-3982@Xerox>
What does (call-next-method) do with optional arguments
which have been defaulted? Does it pass down the values as
defaulted or does it re-default them?
Good question. Off the top of my head, I'd suggest
redefaulting. Any objections?
Isn't there an efficiency (implementation) argument that makes it much
more expensive to do this. If Gregor's early suggestion of
"unpassed-argument" as a value were used for values of optional
arguments that were not passed, then things would be different I think.
∂28-May-87 1511 kempf%hplabsc@hplabs.HP.COM Re: Arguments to CALL-NEXT-METHOD
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 28 May 87 15:10:56 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 28 May 87 15:10:06 pdt
Received: by hplabsc ; Thu, 28 May 87 15:09:09 pdt
Date: Thu, 28 May 87 15:09:09 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8705282209.AA23894@hplabsc>
To: Bobrow.pa@Xerox.COM, kempf%hplabsc@hplabs.HP.COM
Subject: Re: Arguments to CALL-NEXT-METHOD
Cc: Masinter.pa@Xerox.COM, common-lisp-object-system@sail.stanford.edu
What does (call-next-method) do with optional arguments
which have been defaulted? Does it pass down the values as
defaulted or does it re-default them?
Good question. Off the top of my head, I'd suggest
redefaulting. Any objections?
Isn't there an efficiency (implementation) argument that makes it much
more expensive to do this. If Gregor's early suggestion of
"unpassed-argument" as a value were used for values of optional
arguments that were not passed, then things would be different I think.
Yes, it could be more expensive, depending on the implementation
of optionals.
∂28-May-87 1532 Gregor.pa@Xerox.COM Re: Arguments to CALL-NEXT-METHOD
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 28 May 87 15:32:29 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 28 MAY 87 15:27:32 PDT
Date: 28 May 87 15:27 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Arguments to CALL-NEXT-METHOD
In-reply-to: Danny Bobrow <Bobrow.pa>'s message of 28 May 87 14:56 PDT
To: Bobrow.pa@Xerox.COM
cc: kempf%hplabsc@hplabs.HP.COM, Masinter.pa@Xerox.COM,
common-lisp-object-system@sail.stanford.edu
Message-ID: <870528-152732-4022@Xerox>
What does (call-next-method) do with optional arguments
which have been defaulted? Does it pass down the values as
defaulted or does it re-default them?
Good question. Off the top of my head, I'd suggest
redefaulting. Any objections?
Isn't there an efficiency (implementation) argument that makes
it much
more expensive to do this. If Gregor's early suggestion of
"unpassed-argument" as a value were used for values of optional
arguments that were not passed, then things would be different
I think.
The spec is already clear on this point. The arguments are redefaulted.
I see no reason to change the spec on this.
∂28-May-87 2159 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: Arguments to CALL-NEXT-METHOD
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 28 May 87 21:59:19 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 156444; Fri 29-May-87 00:58:41 EDT
Date: Fri, 29 May 87 00:58 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: Arguments to CALL-NEXT-METHOD
To: common-lisp-object-system@sail.stanford.edu
In-Reply-To: <870528-152732-4022@Xerox>
Message-ID: <870529005850.2.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 28 May 87 15:27 PDT
From: Gregor.pa@Xerox.COM
What does (call-next-method) do with optional arguments
which have been defaulted? Does it pass down the values as
defaulted or does it re-default them?
Good question. Off the top of my head, I'd suggest
redefaulting. Any objections?
Isn't there an efficiency (implementation) argument that makes
it much
more expensive to do this. If Gregor's early suggestion of
"unpassed-argument" as a value were used for values of optional
arguments that were not passed, then things would be different
I think.
The spec is already clear on this point. The arguments are redefaulted.
I see no reason to change the spec on this.
I strongly agree. I also don't believe that there is a significant efficiency
cost.
∂29-May-87 1418 Moon@STONY-BROOK.SCRC.Symbolics.COM Object creation discussion (at last!)
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 29 May 87 14:18:39 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 157396; Fri 29-May-87 17:17:59 EDT
Date: Fri, 29 May 87 17:18 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Object creation discussion (at last!)
To: Common-Lisp-Object-System@SAIL.STANFORD.EDU
In-Reply-To: <870523-183530-1635@Xerox>
Message-ID: <870529171806.9.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 23 May 87 18:35 PDT
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
The following is another proposal for instance allocation....
I have been pondering this for a few days. We're getting close to agreement,
I think, but there are a few things about your proposal that bother me.
In this message, I will comment on excerpts from your message that bother me.
In the next message, I will send out a succinct description of how I
see things working, divided up into "necessary" and "optional" features,
with places identified where decisions between alternatives need to be made.
I will use the terminology introduced by Gregor in his message of May 22.
2) divides the instance creation specification between internal and
interface parts (:initargs option). The external part specifies
allowable arguments to make-instance.
I don't think you've completely succeeded in achieving this goal.
Details below. Actually, I doubt that it is feasible to achieve this
goal without major sacrifices in other goals of the standard.
3) assumes optimization of specific calls to make-instance with quoted
arguments so that creating instances can be fast (see Gregor's recent
message), thus allowing removal of the :constructor option.
I agree that we should defer :constructor until we have figured out the
main part of object creation. I don't agree that it has yet been
demonstrated that :constructor is not needed.
The defclass class options are extended to include:
(:initargs (<initarg-name>
[:slotname <slot-specifier>]
[:default-value-form <form>])*)
Each <initarg-name> is a symbol specified to be a legal argument to
make-instance.
<initarg-name> is an abbreviation for (<initarg-name>).
I have two problems with this. For initargs that initialize slots,
this option contains both the declaration and the specification, but
for initargs implemented by methods, this option contains only the
declaration. That seems inconsistent to me, and inconsistent with
your goal of separating the internal and external parts.
The inclusion of the :default-value-form here seems redundant. For
initargs that initialize slots, there is already a way to specify a
default value form in the slot description. For initargs that are
implemented by methods, there is already a way to specify a default
value form in the method parameter list. This :default-value-form
may be based on :default-initargs in an earlier proposal of mine,
but that was something different; :default-initargs was decoupled
from the declaration and specification of initargs, and indeed would
normally appear in a different class. But :default-value-form here
is tightly coupled to the declaration, and to the specification in
the case of initargs that initialize slots.
For each <initarg-name> that has a <default-value-form>, and
does not appear in the init-plist, MAKE-INSTANCE appends <initarg-name>
<value-of-form> to init-plist.
This could be an efficiency problem. I would prefer it if this did not
have to be done for initargs that have not been specified to be
implemented by methods. Defaulting of initargs that initialize slots
can be handled more efficiently, with no need to construct an actual
list of them.
CLASS-INITARGS class &optional local-only
returns the initargs for a standard-class. setf works with
class-initargs when local-only is T.
In my proposal (coming in the next message) I use naming conventions for
this that are more consistent with the 87-003 document. If you've
changed your mind on what naming conventions should be used for the
meta-object functions, please let me know.
ISSUES raised in messages:
1) Lexical proximity (ie why not have an :initarg slot option)
The criterion for simplicity used here is that there should be
exactly one way of specifying legal initargs-names. This simplifies
code for readers who minimize reading of documentation. Another
argument is that specifying initargs is part of the interface, not the
implementation, and hence does not belong with the slot.
I agree with the philosophy of having only one way to do things, but
these arguments are weak, since your :initargs class-option still mixes
implementation with interface, and since (as you point out just below)
readers of code should find out the legal initarg names through a
suitable tool rather than by blundering through code whose documentation
they haven't read.
In my forthcoming proposal, I went back to the :initarg slot-option because
on the whole I think it comes out simpler and better that way. Either way,
there is lexically adjacent information that from some points of view should
be separate and lexically remote information that from some points of view
should be together. I think the congnitive structure is too complex to be
represented in text, and no Lisp syntax can address all points of view. The
environment tools you suggest below seem like a better answer.
I also believe that it is the environment's responsibility to provide
useful views of the class in addition to the text view in the file; for
example, allowing one to see the set of all slots in a class and all
their effective slot-options. Another such view should show the names
of initarg-names that can be used to initialize particular slots.
I certainly believe in this, and my environment does provide the Flavor
equivalents of these features. They're quite useful in practice.
3) How should methods and initargs be kept in synch
Again I believe this is something that a good environment will help
with. No later than the time when the first instance is created, the
environment can warn the user about :initarg-names that are not used for
methods or slot initialization, and methods with illegal argument names.
On 22 April, Gregor said "why is it that I can't count on the methods
getting all the initargs if I use &rest in the lambda-list?" Note that
you can't have it both ways; if the environment does this checking, you
can't use &rest to do your own implementation of the &key mechanism, because
the environment wouldn't be able to figure out what initargs that method
implements.
INITIALIZE-INSTANCE instance &key &allow-other-keys
is the user's procedural handle on initialization. It uses
standard-method-combination. The primary method on standard-object just
returns the instance. One standard way of using initialize will be to
have :before methods, so that all these methods will be fired.
8) Must the user specify &allow-other-keys and :before for
initialize-instance?
A simple macro can add the first or both of these.
Could you explain to my thick skull why
(defmethod-initialize-instance ((x my-class) &key foo bar) ...)
is preferable to and simpler than
(defmethod initialize-instance ((x my-class) &key foo bar) ...)
I believe that this is another example where the standard should be
augmented by a STANDARD library of useful extensions endorsed by the
committee. Other things in that category for me are the macro for
defining simple-method-combination, and the standard simple
method-combination forms (and, or etc.). This is a fourth layer for the
standard.
I think this is a good idea, but I want to warn that we need to be very
careful in how we execute it. If the standard library is only "endorsed"
and not really part of the standard, it is very easy to fall into a Tower
of Babel situation where everyone has their own slightly incompatible
version of the standard library, programs are not really portable, and
programmers can't really understand each other's code. It would be a
shame if that happened. Perhaps if the standard is organized into a
kernel whose description is smaller and can be read in less time, plus
a library, but both are equally well-specified parts of the standard,
it could work. However, I don't think this approach always works;
sometimes the division between "kernel" and "library" seems arbitrary
and only makes the standard seem more complicated.
∂29-May-87 1430 Moon@STONY-BROOK.SCRC.Symbolics.COM Object creation discussion (at last!)
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 29 May 87 14:30:28 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 157424; Fri 29-May-87 17:29:47 EDT
Date: Fri, 29 May 87 17:29 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Object creation discussion (at last!)
To: Common-Lisp-Object-System@sail.stanford.edu
References: <870416002258.1.MOON@EUPHRATES.SCRC.Symbolics.COM>,
<870422172838.5.GREGOR@AVALON.isl.parc.xerox.com>,
<870522-161034-1060@Xerox>,
<870523-183530-1635@Xerox>,
<870527015917.3.MOON@EUPHRATES.SCRC.Symbolics.COM>
Message-ID: <870529172955.0.MOON@EUPHRATES.SCRC.Symbolics.COM>
Object creation seems to divide naturally into eight parts, of which three
are essential and five could optionally be added to provide increased
convenience or customizability. When I say these are optional, I don't mean
that the standard would allow implementations to implement them or not
implement them at their convenience; I mean that we must decide whether to
include them in the proposed standard to gain convenience or customizability,
or to exclude them to gain simplicity or understandability.
I'll discuss how I see each of the eight parts working. I'll use the
declaration/specification/defaulting terminology introduced by Gregor in his
message of 22 May. My language is not precise enough for a final draft, but
I hope the concepts come across clearly this time. For brevity, I have
omitted motivation and philosophy; they have already been discussed in the
mail and can continue to be discussed as needed. In places where there
didn't seem to be a concensus I have included a menu of choices with brief
descriptions.
-foo- means the word foo in italics. FOO means the word foo in boldface.
1. MAKE-INSTANCE and the initarg concept
Objects are created by calling MAKE-INSTANCE. The first argument is a
class or the name of a class, and the remaining arguments are -initargs-
(initialization arguments). Each initarg has a -name-, which is a symbol
(not necessarily a keyword), and a -value-. The arguments to MAKE-INSTANCE,
excepting the first, are alternating names and values of initargs.
MAKE-INSTANCE returns one value, the object that was created.
A programmer -declares- the names of initargs that are valid for a class,
-specifies- the implementation of those initargs (what is done with their
values), and optionally (part 7) supplies -default value forms- for them.
The set of valid initargs for a class is the union of the initargs declared
by the class and its superclasses. MAKE-INSTANCE signals an error if an
initarg is supplied that is not valid.
Inheritance of initarg specifications and defaults is discussed in later
sections.
It is valid for an initarg to be declared more than once, and to be
implemented more than once (for example, an initarg could initialize a slot
and also be used by a method).
We say that an initarg -has a value- if the initarg appears in the arguments
to MAKE-INSTANCE, or if the initarg was defaulted (see part 7).
If the same initarg is given more than once in the arguments to MAKE-INSTANCE,
the leftmost occurrence prevails, as required by Common Lisp.
There is one pre-declared initarg in the standard. Its name is
:ALLOW-OTHER-KEYS, its default is NIL, and its specification is the same as
Common Lisp defines for &KEY argument lists.
2. Initargs that initialize slots
The :INITARG -name- slot-option -declares- an initarg named -name- and
-specifies- that this initarg initializes the slot to which the slot-option is
attached. If the initarg has a value, the value is stored into the slot and
the slot's :INITFORM, if any, is not evaluated. If no initarg specified to
initialize a given slot has a value, then the slot is initialized according to
the :INITFORM (if any).
The :INITARG slot-option is inherited from superclasses. The set of initargs
that initialize a given slot is the union of the initargs declared in :INITARG
slot-options with the same slot name in the class and its superclasses. If
two different initargs that initialize the same slot are given in the
arguments to MAKE-INSTANCE, we have to decide what happens.
2a. The leftmost occurrence in the arguments to MAKE-INSTANCE prevails.
2b. The initarg -declared- by the class that appears earliest in the
class precedence list prevails.
The :INITARG slot-option may be specified more than once for a given slot.
A single initarg can initialize more than one slot if the same initarg name
appears in more than one :INITARG slot-option.
There is no DEFCLASS option that specifies initargs for all the slots,
because that would endorse a particular convention for naming initargs.
3. Initialization methods
After the slots have been initialized, methods for INITIALIZE-INSTANCE are
called. The first argument is the instance and the remaining arguments
are initargs. Defining an INITIALIZE-INSTANCE method that accepts the
value of an initarg with an &KEY parameter -specifies- the implementation
of that initarg. The parameter specifier can also supply a default value
form in the standard way. This default value form affects only the method
in which it appears; it is not a substitute for the facility in part 7.
The value returned by an INITIALIZE-INSTANCE method is ignored; these methods
are used for their side-effects only.
We have to decide between two ways of -declaring- initargs whose
implementation is -specified- by INITIALIZE-INSTANCE methods.
3a. The parameter list of the DEFMETHOD -declares- each &KEY parameter's
keyword-name as an initarg.
3b. Initargs that are not -declared- by a :INITARG slot-option must be
-declared- by a :INITARGS class-option before they can be used. The
syntax is (:INITARGS -name1- -name2- ... ).
We have to decide between two ways of inheriting INITIALIZE-INSTANCE methods.
3c. All INITIALIZE-INSTANCE methods are called, most-specific first.
3d. Standard method combination is used. Normally an INITIALIZE-INSTANCE
method must have a :BEFORE qualifier or use CALL-NEXT-METHOD, otherwise
it would prevent superclasses' initialization methods from being called.
We have to decide whether &REST parameters are allowed in INITIALIZE-INSTANCE
methods.
3e. INITIALIZE-INSTANCE methods must have one required parameter and may
have &KEY parameters; &OPTIONAL and &REST parameters are not permitted.
3f. An INITIALIZE-INSTANCE method may have an &REST parameter, which sees
all of the initargs. ("All" needs to be defined more precisely if the
optional feature of part 7 is adopted; does it necessarily include defaulted
initargs?)
We have to decide whether the parameter list of an INITIALIZE-INSTANCE method
must contain the symbol &ALLOW-OTHER-KEYS.
3g. &ALLOW-OTHER-KEYS is not required.
3h. &ALLOW-OTHER-KEYS is required at the end of every INITIALIZE-INSTANCE
method's parameter list.
EVERYTHING BELOW THIS LINE IS OPTIONAL
4. Allocation methods
The allocation of storage for new instances can be customized by
defining a method for the ALLOCATE-INSTANCE generic function. The
value returned is the instance, with no slot values filled in. The
arguments to an ALLOCATE-INSTANCE method are the same as the arguments
to an INITIALIZE-INSTANCE method, except that the first argument is
the class rather than the instance.
ALLOCATE-INSTANCE uses standard method combination.
There is a default method for ALLOCATE-INSTANCE that does the appropriate
implementation-dependent allocation.
The answers to the choices given in part 3, except for 3c/3d, are identical
for ALLOCATE-INSTANCE and INITIALIZE-INSTANCE methods.
5. MAKE-INSTANCE as a generic function
There are predefined methods for MAKE-INSTANCE selected when the first
argument is a SYMBOL or a STANDARD-CLASS, which implement the behavior
described in part 1. Additional methods can be defined to customize
the behavior of MAKE-INSTANCE for different metaclasses.
6. Initarg accessor functions for class objects
CLASS-DIRECT-INITARGS takes a class and returns a list of symbols that are
names of initargs -declared- for the class.
CLASS-ALL-INITARGS takes a class and returns a list of symbols that are names
of valid initargs for the class.
CLASS-DIRECT-SLOT-INITARGS takes a class and returns a list of
(initarg-name slot-name) lists, with one element for each :INITARG
slot-option in the class.
CLASS-ALL-SLOT-INITARGS takes a class and returns a list of
(initarg-name slot-name) lists, with one element for each :INITARG
slot-option in the class and its superclasses.
7. Defaulting of initargs
A -default value form- can be supplied for an initarg, remotely from the
class that -declares- the initarg's validity and -specifies- the initarg's
implementation.
The :DEFAULT-INITARGS class-option is followed by alternating initarg
names and forms. This class option can appear more than once in a DEFCLASS,
but an error is signalled if an initarg name appears more than once in
:DEFAULT-INITARGS class-options.
This class option is inherited; the set of initargs for a class that are
defaulted is the union of the sets of initargs specified in
:DEFAULT-INITARGS class-options of the class and its superclasses. When
more than one default value form is supplied for a given initarg, the
default value form supplied by the class that appears earliest in the class
precedence list is used.
If an initarg for a class is defaulted, it always -has a value-. If the
initarg does not appear in the arguments to MAKE-INSTANCE, the default
value form is evaluated in the lexical environment of the DEFCLASS form
that supplied it and the resulting value is used as the initarg's value.
The CLASS-DIRECT-INITARG-DEFAULTS function takes a class and returns a
list of (initarg-name default-value-form) lists, with one element for each
:INITARG slot-option in the class.
The CLASS-ALL-INITARG-DEFAULTS function takes a class and returns a
list of (initarg-name default-value-form) lists, with one element for each
:INITARG slot-option in the class and its superclasses.
8. Constructors
I think we should defer talking about the details of constructors, or
even deciding whether or not they are needed, until we have settled the
main part of object creation. So I've deleted part 8 of my discussion.
∂29-May-87 1818 Bobrow.pa@Xerox.COM Re: Object creation discussion (at last!)
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 29 May 87 18:18:20 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 29 MAY 87 18:17:21 PDT
Date: 29 May 87 18:17 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Object creation discussion (at last!)
In-reply-to: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>'s
message of Fri, 29 May 87 17:18 EDT
To: Common-Lisp-Object-System@SAIL.STANFORD.EDU
Message-ID: <870529-181721-1169@Xerox>
Answers to some of the smale questions in your first message:
8) Must the user specify &allow-other-keys and :before
for initialize-instance?
A simple macro can add the first or both of these.
Could you explain to my thick skull why
(defmethod-initialize-instance ((x my-class) &key foo bar) ...)
is preferable to and simpler than
(defmethod initialize-instance ((x my-class) &key foo bar) ...)
My belief was that
(defmethod-init ((x-my-class) &key foo) ...)
would be preferable for some people to
(defmethod initialize-instance :before
((x-my-class) &key foo &allow-other-keys) ...)
Because of its greater conciseness. I would be happy to do without,
since I thin the latter is clearer. Especially since I was not allowing
a new method combination form, and seeing the :before is a useful
reminder. So this special macro has only weak support from me.
I believe that this is another example where the
standard should be augmented by a STANDARD library of useful
extensions endorsed by the committee. Other things in that
category for me are the macro for defining
simple-method-combination, and the standard simple
method-combination forms (and, or etc.). This is a fourth
layer for the standard.
I think this is a good idea, but I want to warn that we need to
be very careful in how we execute it. If the standard library is
only "endorsed" and not really part of the standard, it is very
easy to fall into a Tower of Babel situation where everyone has
their own slightly incompatible version of the standard library,
programs are not really portable, and programmers can't really
understand each other's code. It would be a shame if that
happened. Perhaps if the standard is organized into a kernel whose
description is smaller and can be read in less time, plus a
library, but both are equally well-specified parts of the standard,
it could work. However, I don't think this approach always works;
sometimes the division between "kernel" and "library" seems
arbitrary and only makes the standard seem more complicated.
My idea here is that instead of providing a specification for things in
the library, we provide reference code that is part of the standard. It
is expected that it is this code OR CODE THAT HAS IDENTICAL EFFECT that
will be provided in the system IF ANYTHING BY THIS NAME IS IN THE
SYSTEM.
∂29-May-87 2300 RPG Object Creation (at last!)
To: common-lisp-object-system@SAIL.STANFORD.EDU
In case people care, I am now relatively back in the loop on CLOS.
I have been reading the initialization messages since last weekend
trying to understand them.
I am on the midst of writing a message with an alternative to
Moon's proposal. My proposal is less involved, more radical, more
CLOSsy than Moon's. So that people will not think that I am
lending support to Moon's proposal by my silence, I want to make
clear that I regard Moon's proposal as an abomination. Unless some
revelation comes to me that convinces me it's the right approach
(contrast this with being convinced it's the right thing) adoption
of his proposal is sufficient for me to withdraw my support of CLOS.
-rpg-
∂31-May-87 1313 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 31 May 87 13:13:45 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 31 MAY 87 13:13:16 PDT
Date: 31 May 87 13:12 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Object creation discussion (at last!)
In-reply-to: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>'s
message of Fri, 29 May 87 17:29 EDT
To: Moon@STONY-BROOK.SCRC.Symbolics.COM
cc: Common-Lisp-Object-System@sail.stanford.edu
cc: Gregor.pa@Xerox.COM, Bobrow.pa@Xerox.COM
Message-ID: <870531-131316-1924@Xerox>
This message outlines a different approach for handling initargs which
initialize slot values. The basic idea is that all initarg processing
should be defined procedurally, and so should be moved into
initialize-instance methods. An effect of this is that -specification-
as defined in my earlier message disappears from defclass. In this
'proposal' defclass only does initarg -declaration- and -defaulting-.
I will present this idea in the form of a sketchy proposal and some
comments. This proposal certainly not fully fleshed out, but I believe
it is well enough worked out that we can use it as a basis for talking
about what it would be like to make all initarg processing be defined in
a procedural way.
In this proposal, there are two defclass options, a new macro called
intialize slots, and make-instance works differently than in previous
proposals.
The two defclass options:
- :legal-initargs
This just -declares- the legal initargs for this class. This
option is inherited in the obvious simple way. The set of legal
initargs for a given class is the union of the legal-initargs of
all the classes in the class precedence list.
- :default-initargs
This is used to -default- values for initargs. Notice that it is
completely orthogonal to -declaration-.
Here are a couple examples of using defclass with these options:
;;;
;;; position is an abstract class. It doesn't make sense to make
;;; instance of it all by itself. It has to be mixed in with a
;;; class which handles the :x-position and :y-position initargs.
;;;
(defvar *default-position-x* 0)
(defvar *default-position-y* 0)
(defclass position () ()
(:default-initargs :x-position *default-position-x*
:y-position *default-position-y*))
(defclass x-y-position (position) (x y)
(:legal-initargs :x-position y-position))
The initialize-slots macro is used in initialize-slots methods to help
in processing initargs which initialize slot values. Here is an example
of using it:
(defmethod initialize-instance :before
((p x-y-position) &allow-other-keys &rest initargs)
(initialize-slots p initargs
(:x-position x)
(:y-position y)))
This macro just expands into something like:
(defmethod initialize-instance :before
((p x-y-position) &allow-other-keys &rest initargs)
(apply #'(lambda (&key ((g001 :x-position)) ((g002 :y-position)))
(setf (slot-value p 'x) g001)
(setf (slot-value p 'y) g002))
initargs))
make-instance proceeds by:
1: taking the initargs it is passed and combining them with the
:default-initargs to get the total set of defaulted initargs.
2: calling allocate-instance with the class and the total set of
defaulted initargs to get the new instance.
3: evaluating ALL of the slot :initforms and setting the values of the
slots as specified.
4: calling initialize-instance with the new instance and the complete
set of defaulted initargs.
5: returning the instance.
COMMENTS:
Obviously, the major change in this proposal is that all initarg
processing is defined procedurally using lisp and other primitive
mechanisms of CLOS. I think this is a significant difference. It is
the driving force behind this proposal. Without going into details now,
all the general advantages of using a procedural mechanism based on lisp
rather than a special purpose declarative mechanism apply.
One point I should make is that I don't believe this protocol will run
any slower than previous protocols in cases where the two do the same
work. To be specific, I believe that it is possible, and in fact not
difficult, to make this protocol be as efficient as the new flavors
mechanism for cases where the two are equivalent. Because this is an
important issue I think we should address it explicitly but I would like
to do so in a different message.
Notice (I am sure you have already) that in this proposal, the
:initforms are ALWAYS evaluated. My answer to this is that I consider
that a feature of this proposal. One way of looking at what was
happening before is that there was a declarative mechanism for
specifying that an :initform should not be evaluated if certain initargs
were present. As with all such declarative mechanisms, only certain
pre-defined patterns of such conditionalization were supported. In this
new proposal, if you have an internal initial value (:initform) which
you only want to evaluate if certain initargs are not supplied, move it
to the initialize-instance method for that class. There you can do all
the fancy conditional evaluation you want.
∂31-May-87 1439 masinter.pa@Xerox.COM Re: Object Creation (at last!)
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 31 May 87 14:39:23 PDT
Received: from Semillon.ms by ArpaGateway.ms ; 31 MAY 87 14:38:53 PDT
From: masinter.pa@Xerox.COM
Date: 31 May 87 14:38:27 PDT
Subject: Re: Object Creation (at last!)
In-reply-to: RPG@SAIL.STANFORD.EDU's message of 29 May 87 23:00 PDT
To: Dick Gabriel <RPG@SAIL.STANFORD.EDU>
cc: common-lisp-object-system@SAIL.STANFORD.EDU
Message-ID: <870531-143853-1952@Xerox>
Everyone has, as their last resort, the withdrawal of support for the
entire proposal. However, I think that we will arrive at a better
standard if we approach it in the spirit of cooperation. I think there
is a shared sense of uneasiness about any unnecessary complexity. I
don't think you need to threaten us with withdrawal for your alternative
to be heard and considered.
Peace,
Larry
∂31-May-87 1644 RPG Object creation discussion (at last!)
To: common-lisp-object-system@SAIL.STANFORD.EDU
I spent a day last weekend reading the discussion about initialization.
I'm not sure I understand the issues very well, and I'm certain I don't
understand them as well as Moon and Gregor. Nevertheless, I believe that
the whole approach needs to be questioned. It might turn out that Moon's
approach is the best of a number of lousy alternatives, but let's give
something else a shot.
The problem of creating an instance is a combination of two things:
allocating storage for the instance and then initializing the slots of the
instance. It makes sense to want to customize various parts of this
process, and a mechanism like the one for changing class seems appropriate
- when an instance is to be created, several generic functions are
invoked, one to allocate storage and the other to initialize the instance;
the user can define methods on those functions. In this message I will
ignore the issue of ALLOCATE-INSTANCE.
DEFCLASS has an :initform slot option, and I imagine that almost everyone
is going to be happy with that. I can imagine adventuresome people will
call the vanilla MAKE-INSTANCE and then do a number of SETF's to get
things right. The question becomes how often a hairier initialization
protocol will be needed.
The most sophisticated uses of initialization involve inheriting
initialization behavior when that behavior is non-trivial. That is,
there is already a means of inheriting the :initform forms, and we now
are questioning how to inherit more complex behavior.
Generic functions and the class hierarchy are the means CLOS provides
for inheriting behavior. It is powerful and sophisticaed, particularly
in terms of of method combination. Inheritance of slot descriptions is
the means for inheriting structure and description. Because simple
initialization and nothing more is frequently needed, the :initform option
was provided as part of the description of a class, whereas initialization
is clearly more like a behavior (like SETF) than a description (like
classes having slots).
Another goal of the initialization protocol is to effect some mapping
between the arguments to MAKE-INSTANCE and the allocation/initialization
activities. During the process we'd like defaulting to happen as well.
I don't see that initialization is a declarative process; furthermore,
considering it to be declarative leads to the use of a
programming-in-keywords style, which is odious. The only sense in which
it ought to be declarative is that that is a more natural means for
achieving goal of literally declaring the valid arguments to MAKE-INSTANCE.
Other than that, the only motivation for making hairy initialization
declarative is that simple initialization is declarative.
There seems to be another goal for the various proposals, which is to
provide a means to specify an external name for a slot, to be used during
initialization, while the internal slot remains hidden.
There is already a feature to provide an alternative name for a slot,
an external name if you will; and that feature is the accessor method.
In fact, with methods and setf methods one can provide a totally
abstract interface to otherwise-uninteresting instance-provided storage.
I believe that the features of a CLOS without an initialization protocol
ought to be powerful enough to write that initialization protocol.
Let's look at a variant of Danny's example; the syntax I use here
to express what the initialization should do is reminiscent of that in the
various proposals:
(defclass point ()
((x :initform 0 :initarg :moosebird1)
(y :initform 0 :initarg :moosebird2))
(:initargs :rho :theta))
The intention is that X and Y are the internal names of slots and that the
user would prefer to use the more mneumonic names of :MOOSEBIRD1 and
:MOOSEBIRD2 to initialize X and Y. The :initargs class option indicates
that RHO and THETA might be supplied instead of MOOSEBIRD1 and MOOSEBIRD2.
(defclass picture (point)
(bitmap saved-bitmap)
(:initargs
(:moosebird2 :default-value-form *screen-top*)
(:image :slotname (bitmap saved-bitmap))))
Here we want the creation of an instance of PICTURE to make the Y (MOOSEBIRD2)
coordinate of the POINT to be *screen-top* if it isn't supplied to
MAKE-INSTANCE. If :IMAGE is supplied, it supplies the value of the slots
BITMAP and SAVED-BITMAP. I think this syntax is more like Danny's than
Moon's, but it doesn't matter.
It would seem that generic functions and setf methods ought to be able to
handle the needs of these initialization tasks. One could imagine that a
user would want to write a CLOS program that would classify objects based
on changing hypotheses, and that program would want to perform,
essentially, re-initialization or tasks just like it. If CLOS is not able
to support programming like initialization at the user level using
methods, I think we will have failed in our language design.
I will now try to express the initialization needs of this setup
using methods rather than options and see what happens. I do this
to explore the degree to which we have failed to provide mechanisms
sufficient to perform initialization.
(defclass point ()
((x :initform 0)
(y :initform 0)))
First we'll need some methods for RHO and THETA because these abstract
slots don't appear in the DEFCLASS:
(defmethod rho ((p point))...)
(defmethod theta ((p point))...)
(defmethod-setf rho ((p point)) (rho)...)
(defmethod-setf theta ((p point)) (theta)...)
Sometimes the user will supply an X and a Y and sometimes a RHO and a
THETA when he calls MAKE-INSTANCE. However, when the user supplies an X
and a Y, he will use the names MOOSEBIRD1 and MOOSEBIRD2 (we use English
words so we don't have to apologize).
Here's the DEFCLASS for PICTURE:
(defclass picture (point)
(bitmap saved-bitmap))
When a picture is initialized, we want the Y slot to be initialized
to *screen-top*.
Here's a shot at how this looks if we define methods on INITIALIZE-INSTANCE
ourselves:
(defmethod initialize-instance
((p point)
&key (moosebird1 0 mb1-p)
(moosebird2 0 mb2-p)
(rho 0 rho-p)
(theta 0 theta-p)
&allow-other-keys)
;; Maybe we should worry about mixtures of MOOSEBIRD1/MOOSEBIRD2 and
;; RHO/THETA???
(when mb1-p (setf (x p) moosebird1))
(when mb2-p (setf (y p) moosebird2))
;; Something really ugly is in here:
(when (or rho-p theta-p) (let (...) (setf (x p) ...)...))))
Now for initializing PICTURE:
(defmethod initialize-instance
((pict picture)
&key
(moosebird2 *screen-top)
(image nil image-supplied)
&allow-other-keys)
(call-next-method) ;maybe? Or use some method combination?
(when image-supplied
(setf (bitmap pict) image)
(setf (saved-bitmap pict) image))
(setf (y pict) moosebird2))
Hm, well, I'm not sure this is right, but let's move on to look at
MAKE-INSTANCE:
(defmethod MAKE-INSTANCE
((pict picture) &key moosebird1 moosebird2 rho theta image)
(let ((instance (allocate-instance (class-named 'picture)))
(initialize-instance pict moosebird1 moosebird2 rho theta image)))
Well, this seems pretty ugly, plus it's probably wrong. I suppose Moon's
proposal solves all of these problems.
On the other hand, this approach has to look better than this. Generic
functions are supposed to provide modularity and abstraction. Why can't
we achieve it here?
Also, we expect that generic function discrimination should be able to
help us sort out the keyword arguments we need to specify for the
various methods on INITIALIZE-INSTANCE. We've got a lot of logic in
the method on INITIALIZE-INSTANCE for PICTUREs, and that logic looks a
lot like what someone might write to mimic generic function dispatch
if he didn't have it.
Unfortunately, Common Lisp provides bad language design exactly at the
point where we want to attack the problem.
Consider the nature of parameters to functions. In Common Lisp there are
these two notions: positional arguments and named arguments. In the first
case values are associated with variables depending on the positions in
which the arguments are passed. In the latter case, the binding happens
depending on the names of the arguments, which are passed along with the
arguments.
For example:
(defun f (x y &key a b) ...)
(f 1 2 :b 3 :a 4)
X and Y are positional, and A and B are named.
There is a second pair of notions: required arguments and optional arguments.
Does Common Lisp have all of the combinations of these notions?
| positional | named |
-------------------------------
required | yes | no |
-------------------------------
optional | yes | yes |
-------------------------------
It doesn't seem so. Keyword arguments combine named and optional.
We discriminate in generic functions based on required arguments. Suppose
we had named required arguments as distinct from named optional arguments,
and suppose we discriminated on the classes of all required arguments
and on the names of the named required arguments.
(defmethod foo (x y &required-key foo bar) `(foobar ,x ,y ,foo ,bar))
(defmethod foo (x y &required-key baz ola) `(bazola ,x ,y ,baz ,ola))
The behavior I imagine is demonstrated here:
(foo 1 2 :foo 3 :bar 4) => (foobar 1 2 3 4)
(foo 1 2 :baz 3 :ola 4) => (bazola 1 2 3 4)
(foo 1 2 :foo 3 :ola 4) => error
(foo 1 2 :foo 3 :bar 4 :ola 5) => error
Of course, required keyword arguments can be discriminated on in the usual
way as well.
Consider a slightly different pair of methods:
(defmethod foo (x y &required-key foo bar &allow-other-keys)
`(foobar ,x ,y ,foo ,bar))
(defmethod foo (x y &required-key baz ola &allow-other-keys)
`(bazola ,x ,y ,baz ,ola))
One question is which of the two methods on FOO above is more specific
than the other? That is, suppose we write
(foo 1 2 :foo 3 :bar 4 :baz 5 :ola 6)
Which method in invoked?
The answer depends on whether one subscribes to the idea that a total
ordering on methods is necessary, once the arguments are known. I think
it isn't necessary, and I am willing to adopt either one or several
approaches. One is that the ordering is unspecified and effectively
random. The second is that some ambiguous uses of &required-keys (with
&allow-other-keys or :allow-other-keys t) only might make sense within
certain method combination regimes. The regime I will use in the examples
below explicitly are indicated with the qualifier :progn - using it, all
applicable methods are applied.
[Aside:
One could go further with this approach, but it isn't needed for the purposes
of doing initialization in the example shown. Here is the extension of this
approach for the curious reader:
Let's also suppose that if no method on a generic function has optional
arguments, discrimination happens only among methods with the corresponding
numbers of supplied arguments:
(defmethod foo (x) 'one-argument)
(defmethod foo (x y) 'two-arguments)
(defmethod foo (x y z) 'three-arguments)
(foo 1) => one-argument
(foo 1 2) => two-arguments
(foo 1 2 3) => three-arguments
Notice that we no longer have a need for optional arguments at all! Here's
an example:
(defun foo (x &optional (y 77 y-supplied))<code>)
=>
(flet ((f (x y y-supplied) <code>))
(defmethod foo (x y) (f x y t))
(defmethod foo (x) (f x 77 nil)))
or your favorite alternative. of course, when we add in optional keyword
arguments this can get tiresome.]
One major problem with this approach is that it is a generalization of the
notion of generic function in a direction none of us has ever bought
into before. Currently a generic function is a mechanism for examining the
classes of some of the arguments supplied to it and deciding which
method or methods to invoke and how to combine them if more than one
is invoked. This generalization alters that to be as follows:: A generic
function is a mechanism for examining the arguments supplied to it and
deciding which method or methods etc.
Currently we discriminate on the class or identity of an argument, the latter
being similar to a singleton class. This proposal allows us to discriminate
on the name of an argument, and maybe we don't want to do that.
Now let's look at initialization on the above example using the notion
of &required-keys.
(defclass point ()
((x :initform 0)
(y :initform 0)))
(defmethod initialize-instance :progn
((p point) &required-key moosebird1 moosebird2 &allow-other-keys)
(setf (x p) moosebird1)
(setf (y p) moosebird2))
I use the method qualifier ``:progn'' to signify that all the methods that
are applicable are run. I suppose this is in most-general to least-general
order. If some other combination order is correct, that fact is
unimportant to my exploration. Notice that the &required-keys serve to
map the names MOOSEBIRD1 and MOOSEBIRD2 onto the slots named X and Y.
Additionally, the &required-keys select this method based on the named of
the named arguments.
(defmethod initialize-instance :progn
((p point) &required-key rho theta &allow-other-keys)
(let (...)
(setf (x p)...)
(setf (y p)...)))
Either the method for MOOSEBIRD1/MOOSEBIRD2 or the one for RHO/THETA is
selected based on which pair of named arguments are supplied to
MAKE-INSTANCE. If we are willing to expect that any combination might
be supplied, we can write:
(defmethod initialize-instance :progn
((p point) &required-key moosebird1 &allow-other-keys)
(setf (x p) moosebird1))
(defmethod initialize-instance :progn
((p point) &required-key moosebird2 &allow-other-keys)
(setf (y p) moosebird2))
and so on.
Now let's look at PICTURE:
(defclass picture (point)
(bitmap saved-bitmap))
(defmethod initialize-instance :progn
((pict picture) &required-key image &allow-other-keys)
(setf (bitmap pict) image)
(setf (saved-bitmap pict) image))
(defmethod initialize-instance :progn
((pict picture) &key (moosebird2 *screen-top*) &allow-other-keys)
(setf (y pict) moosebird2))
Now MAKE-INSTANCE is easy, as it was before:
(defmethod MAKE-INSTANCE
((pict picture) &rest all)
(let ((instance (allocate-instance (class-named 'picture)))
(apply #'initialize-instance pict all))))
This is definitely more verbose than the other proposals, but it is verbosity
used in rare occasions. Also, the conceptual overhead is lower, because
programmers will already need to know how to write methods and will already
understand how to combine them. Finally, the new aspect of method discrimination
that makes this approach palatable has additional expressive power.
Maybe we don't want to go with an approach like this one, but I think that
the needs of people who would want to write a program whose actions are
like initialization are important enough that we should make sure that
CLOS can handle them.
-rpg-
∂01-Jun-87 2132 Moon@STONY-BROOK.SCRC.Symbolics.COM object / cleanup subcommittee interaction
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 1 Jun 87 21:32:30 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 161293; Tue 2-Jun-87 00:32:04 EDT
Date: Tue, 2 Jun 87 00:32 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: object / cleanup subcommittee interaction
To: Common-Lisp-Object-System@sail.stanford.edu
Message-ID: <870602003210.7.MOON@EUPHRATES.SCRC.Symbolics.COM>
Does anyone have a list of the issues that we wanted the cleanup
committee to address? I remember something about being able to put
generic functions into function cells, a couple of things about cleaning
up the builtin types, the type FUNCTION, and the thing about &key
argument indicators that aren't keywords. The latter two have been
taken care of, the former two haven't and I'm not sure I remember them
too well. Were there any others?
∂02-Jun-87 1029 RPG object / cleanup subcommittee interaction
To: common-lisp-object-system@SAIL.STANFORD.EDU
I assumed that a generic function was a function and so could appear in
a function cell. Doesn't the Concepts chapter state that
(typep <generic function> 'function) => T
I presume that a generic function is a function under the cleaned-up
definition.
Moon, do you know the date of your message discussing the non-keyword &key
arguments? What are the considerations?
I think there were no other problems except for a recommendation to
design a DEFRECORD facility to replace DEFSTRUCT now that DEFSTRUCT is
sort of obsolete.
-rpg-
∂02-Jun-87 1203 Bobrow.pa@Xerox.COM Re: object / cleanup subcommittee interaction
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 2 Jun 87 12:03:01 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 02 JUN 87 11:48:05 PDT
Date: 2 Jun 87 11:48 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: object / cleanup subcommittee interaction
In-reply-to: Dick Gabriel <RPG@SAIL.STANFORD.EDU>'s message of 02 Jun 87
10:29 PDT
To: common-lisp-object-system@SAIL.STANFORD.EDU
Message-ID: <870602-114805-4200@Xerox>
Other cleanup issues:
Making FUNCTION be a genuine type (distinct from CONS)
Making PATH-NAME, HASHARRAY etc be distinct from other types so we can
have a class
(i.e. making these be distinguishable by the type system from an
implementation type e.g. array)
∂02-Jun-87 1642 kempf%hplabsc@hplabs.HP.COM Re: object / cleanup subcommittee interaction
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 2 Jun 87 16:41:55 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Tue, 2 Jun 87 16:36:27 pdt
Received: by hplabsc ; Tue, 2 Jun 87 16:35:16 pdt
Date: Tue, 2 Jun 87 16:35:16 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706022335.AA00365@hplabsc>
To: Common-Lisp-Object-System@sail.stanford.edu,
Moon@STONY-BROOK.SCRC.Symbolics.COM
Subject: Re: object / cleanup subcommittee interaction
Yes. The need for a LOAD-TIME-EVAL function. Most lisps have this
functionality anyway, to implement #, but it needs to available
from macrogenerated code as well. I use it in COOL and I believe
it is used in CALL-NEXT-METHOD.
Other than that, something like the LET-PSEUDO which we use in
HP Lisp to implement lexical instance variables would make
WITH-SLOTS somewhat cleaner, by not requiring a code walk. The
general idea is to have a symbol macro facility, which allows
forms to be substituted for symbols. Careful study would be
required to determine where in the macroexpand-evaluate loop
to insert expansion of symbol macros, however.
jak
∂02-Jun-87 2022 Bobrow.pa@Xerox.COM Re: Object creation discussion (at last!)
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 2 Jun 87 20:22:11 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 02 JUN 87 20:16:33 PDT
Date: 2 Jun 87 18:37 PDT
From: Bobrow.pa@Xerox.COM
Subject: Re: Object creation discussion (at last!)
In-reply-to: Gregor.pa's message of 31 May 87 13:12 PDT
To: Common-Lisp-Object-System@sail.stanford.edu
Message-ID: <870602-201633-1444@Xerox>
This message proposes another variant on initialization that has in
common with Gregor's and RPG's that it pushes all initialization into
initialization methods. It is most like Gregor's, but has NO new class
options and no new mechanism for calling generic functions. Its
properties are:
1) Legality checking of make-instance arguments is made an environmental
issue.
2) All :initforms are evaluated (as in Gregor's message);
allocate-instance returns an instance with all the values specified by
:initforms filled in.
3) Default values for initargs are computed a special method
4) Standard initialization methods are :after methods, so that more
specialized methods run after less specialized ones. Initialization of
slots is done in these :after methods.
5) Standard macros can provide convenience for the user and allow hooks
into the environment, and probably optimization. By standard I mean in
the sense of my last message, with a reference implementation.
Here is a cut at a more detailed description:
(defmethod make-instance ((c standard-class) &rest initargs)
(let ((o (allocate-instance c)))
;o is an object with slots filled in by :initforms
(apply #'initialize-instance o (initial-args o initargs))
o)
(defmethod initial-args ((o standard-object) initargs)
initargs)
Suppose for objects of class position one wanted to have
default-initargs :x with default value (compute-x).
Then one would write a method:
(defmethod initial-args ((o position) initargs)
(call-next-method o
(if (get initargs ':x) initargs
(list* ':x (compute-x) initargs))))
The obvious convenient macro would allow one to write
(defmethod-initial-args position (:x (compute-x) :y (compute-y)...))
Suppose one wanted to have :x set the slot x, and :rho to do something
else. One would write
(defmethod initialize-instance :after
((o position) &key (rho :rho) (g002 :x g0002-p)
&allow-other-keys)
(when g0002-p (setf (slot-value x) g002))
... ; do rho stuff)) )
An obvious macro for supporting this might allow
(defmethod-init-after ((o position) &key (rho :rho)) (:x x ...)
... ;do rho stuff)
where defmethod-init-after inserts the :after, &allow-other-keys, and
the arguments used for the slot-value setting, as well as generating
the code.
Arguemnt checking.
I assume here that the set of legal arguments to intialize-instance are
just those that are explicit in some method of initialize-instance, and
some environmental facility will provide appropriate warnings (very fast
hand waving here).
Optimization
I have also ignored any discussion here of how optimized calls to
make-instance could be managed, but I believe it could be done. (more
fast hand waving).
∂03-Jun-87 1220 Bobrow.pa@Xerox.COM Re: Floats
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 3 Jun 87 12:20:41 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 03 JUN 87 11:01:14 PDT
Date: 3 Jun 87 11:01 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Floats
In-reply-to: Dick Gabriel <RPG@SAIL.STANFORD.EDU>'s message of 27 May 87
11:24 PDT
To: RPG@SAIL.STANFORD.EDU
cc: common-lisp-object-system@SAIL.STANFORD.EDU
Message-ID: <870603-110114-2066@Xerox>
This problem needs to be solved in several parts:
1) We need a way in CLOS to have more than one name for a particular
class. A class should have at most one primary name, the one it
provides as value of (class-named class). I suggest a function
(set-class-name class name &optional primary-name-p)
This will allow us to add names such as FLOAT-24-32 to SHORT-FLOAT
2) We need a mechanism to go from class descriptions to classes,
something like:
(get-class-from-description superclass-name semantic-description).
It would use system dependent descriptions of classes, and a matching
procedure.
e.g. (get-class-from-description
'FLOAT
(AND (MANTISSA 24 32) (EXPONENT 6 10)))
Classes that need such matching might have a property describing
themselves, and a metaclass that knows how to match descriptions, so the
search could be a recursive tree walk from a super.
3) Methods should be defined on semantic-based classes, e.g.
FLOAT-24-32. The real problem for a user is when he/she defines methods
on two classes with different names, and they turn out to be defined on
the same class. Thus one mthod replaces the other. If each method
defined by defmethod remembered the names under which it were defined,
then an appropriate warning could be issued when a replacement of this
kind happened.
4) This solves the FLOAT problem provided CommonLisp has a reasonable
semantics. I do not claim to understand this at all. If it does not,
then this must be solved separately.
∂03-Jun-87 1221 Gregor.pa@Xerox.COM Re: object / cleanup subcommittee interaction
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 3 Jun 87 12:21:08 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 03 JUN 87 11:32:13 PDT
Date: 3 Jun 87 11:31 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: object / cleanup subcommittee interaction
In-reply-to: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>'s
message of Tue, 2 Jun 87 00:32 EDT
To: Moon@STONY-BROOK.SCRC.Symbolics.COM
cc: Common-Lisp-Object-System@sail.stanford.edu
Message-ID: <870603-113213-2135@Xerox>
Yes, load-time-eval is, I think an important issue for the cleanup
committee.
I also think that providing constructors and accessors for lexical
environments is important. I don't know what committee that is supposed
to fall under, but it would be good to get it fixed as soon as possible.
As I have said before, I would rather see us do that right than add
symbol macros to the language.
∂03-Jun-87 1455 kempf%hplabsc@hplabs.HP.COM Re: object / cleanup subcommittee interaction
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 3 Jun 87 14:55:16 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Wed, 3 Jun 87 14:54:34 pdt
Received: by hplabsc ; Wed, 3 Jun 87 14:53:08 pdt
Date: Wed, 3 Jun 87 14:53:08 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706032153.AA14903@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: Re: object / cleanup subcommittee interaction
I second Gregor's proposal for providing constructors and accessors
for lexical environments. Environments are underspecified in
CLtL, resulting in confusion in implementation.
∂03-Jun-87 1709 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 3 Jun 87 17:09:26 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 03 JUN 87 17:00:29 PDT
Date: 3 Jun 87 17:00 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Object creation discussion (at last!)
In-reply-to: Dick Gabriel <RPG@SAIL.STANFORD.EDU>'s message of 31 May 87
16:44 PDT
To: RPG@SAIL.STANFORD.EDU
cc: common-lisp-object-system@SAIL.STANFORD.EDU
Message-ID: <870603-170029-2690@Xerox>
In this message I address what I think is an important point which Dick
happened to mention in his message. Specifically, its important that
whatever the special purpose mechanisms we might want to include in the
initialization protocol are, it should be possible to implement those
using more primitive CLOS.
Specifically, I will look at initarg -defaulting-. I will show that it
is just a specific instance of a more general problem, and I will show
two different ways that problem can be implemented in CLOS. I will also
show how the kinds of optimizations which are desirable can be
implemented in CLOS.
There is a lot of stuff in this message. A lot of this message is
sample code. I know that makes it somewhat dense and I apologize, but I
think the points are important. I hope that at least the following come
across:
- two different ways of thinking about how default initarg inheritance
works.
- how to implement functionality like default initarg inheritance in
CLOS.
- some more examples of the kinds of things the meta-object protocol
is good for.
Initarg defaulting is just a specific instance of the more general
problem of computing a value for a class from component values provided
by all the classes in the class precedence list. Seen as such, there
are two different mechanisms for doing this in CLOS. I will call these
the "structural" and the "procedural" point of view.
In these sample implementations, I will just implement the collection of
the default initargs for a class. These implementations do not take
care of merging the initargs provided in the call to make-instance with
the default values to get the 'total, defaulted, evaluated initargs'.
In a separate message Danny or I will show an interesting way to do that
using the procedural implementation.
In all examples, assume the following class structure, with the
per-class default-initargs as annotated:
menu ((:highlighting :invert)
\ (:expose-near *default-expose-near*))
\
\
color-menu ((:highlighting *highlight-color*))
\
\
editor-menu ((:expose-near *editor-window*))
so that the value returned by
(class-default-initargs (class-named 'editor-menu))
should be
((:expose-near *editor-window*) (:highlighting *highlight-color*))
PROCEDURAL IMPLEMENTATION:
;;;
;;; For each class, define a method on class-default-initargs which
contributes
;;; that class's initargs. The structure is that the initargs for a
particular
;;; class get consed onto the initargs for its superclasses (using
list*). The
;;; primary method on OBJECT provides the NIL for the base of the
consing. The
;;; :around method on OBJECT provides mechanism for removing duplicated
initargs
;;; from the rest of the list.
;;;
(defmethod default-initargs ((c object))
())
(defmethod default-initargs :around ((c object))
(remove-duplicates-from-plist (call-next-method) :from-end 't))
;;;
;;; Here are the methods for the sample classes.
;;;
(defmethod default-initargs ((c menu))
(list* '(:highlighting :invert)
'(:expose-near *default-expose-near*)
(call-next-method)))
(defmethod default-initargs ((c color-menu))
(list* '(:highlighting *highlight-color*)
(call-next-method)))
(defmethod default-initargs ((c editor-menu))
(list* '(:expose-near *editor-window*)))
STRUCTURAL IMPLEMENTATION:
;;;
;;; For classes, define a new class option, :default-initargs, which is
used to
;;; specify the default initargs for that class. The
class-default-initargs
;;; generic function just goes and collects the contributions from all
the
;;; classes merges them together.
;;;
(defclass my-standard-class (standard-class)
((local-default-initargs :initform ()
:accessor class-local-default-initargs)))
;;;
;;; Any class which isn't an instance of my-standard-class has local
default
;;; initargs of (). It is an error to try and set the local default
initargs
;;; of a class which isn't an instance of my-standard-class.
;;;
(defmethod class-local-default-initargs ((class standard-class))
())
(defmethod-setf class-local-default-initargs ((class standard-class))
(nv)
(error "can't set the default initargs of ~S". class))
(defmethod legal-class-option-p ((class my-standard-class) option)
(eq option ':default-initargs))
(defmethod update-class ((class my-standard-class) &key options
&allow-other-keys)
(setf (class-local-default-initargs class)
(getf options :default-initargs))
(call-next-method))
(defun class-default-initargs (class)
(remove-plist-duplicates
(apply #'append
(mapcar #'class-local-default-initargs
(class-precedence-list class))))
:from-end 't))
An obvious problem with both of these implementations is that every time
the class-default-initargs function is called the value is consed up.
Certainly in initialization we would want to be able to optimize this by
caching the result, and it is reasonable to expect that much user code
might want to do so as well. This is also easy to do using CLOS.
PROCEDURAL IMPLEMENTATION (cached version):
In this implementation, in order to make things more simple, we use a
special macro define-default-initargs-method to define the special kinds
of methods on default-initargs. This special macro isn't absolutely
necessary, it just makes the code presented here a little simpler.
(defclass default-initargs-method (standard-method)
((initargs :initform nil
:accessor method-initargs)))
(defmacro define-default-initargs-method (class-name initargs)
`(define-default-initargs-method-1 ',class-name
',initargs
#'(lambda (ignore) ',initargs)))
(defun define-default-initargs-method-1 (class-name initargs fn)
(let* ((class (class-named class-name))
(specs (list class))
(old (get-method #'default-initargs () (list (class-named
class-name)) ()))
(new (make-instance 'default-initargs-method :function fn
:specializers
specs
:initargs
initargs)))
(when old (remove-method #'default-initargs old))
(add-method #'default-initargs new)))
(defgeneric-options default-initargs (class))
;;;
;;; add a method to compute effective method for default-initargs which
will take care of
;;; producing a special effective method when all the methods are of the
special kind.
;;;
;;; if there are any methods on default-initargs that were defined with
defmethod, we will
;;; just revert to ordinary standard method combination. In this way,
we get the optimization
;;; when we can have it, but when someone wants to put a method on
default-initargs that needs
;;; to compute that will work just fine.
;;;
(add-named-method 'compute-effective-method
'(gfun methods type args)
`(',#'default-initargs)
#'(lambda (gfun methods ignore ignore)
(if (every #'(lambda (m) (typep m
'default-initargs-method))
methods)
<make optimized method>
(call-next-method))))
Where <make-optimized-method> produces a method which just has all the
constants collected up in it.
STRUCTURAL IMPLEMENTATION (cached version):
For the structural implementation, much of the code is the same. We
just use the propagate-class-update generic function to maintain a cache
of the proper value. Note that this implementation is not the best
possible. In particular, it recomputes the class-default-initargs
anytime any aspect of a class changes. This is not hard to fix, I have
just done the simplest of the caching implementations here. The reason
being that a more spohisticated structural caching implementations would
have the same structure, it would hook itself into the class update
protocol the same way, but it would be harder to read.
;;;
;;; For classes, define a new class option, :default-initargs, which is
used to
;;; specify the default initargs for that class. The
class-default-initargs
;;; generic function just goes and collects the contributions from all
the
;;; classes merges them together.
;;;
(defclass my-standard-class (standard-class)
((local-default-initargs
:initform ()
:accessor class-local-default-initargs))
(default-initargs
:initform ()
:reader class-default-initargs)))
;;;
;;; A class which isn't an instance of my-standard-class has local and
total
;;; default initargs of (). It is an error to try and set the local
default
;;; initargs of a class which isn't an instance of my-standard-class.
;;;
(defmethod class-local-default-initargs ((class standard-class))
())
(defmethod-setf class-local-default-initargs ((class standard-class))
(nv)
(error "can't set the default initargs of ~S". class))
(defmethod class-default-initargs ((class standard-class))
())
(defmethod legal-class-option-p ((class my-standard-class) option)
(eq option ':default-initargs))
(defmethod update-class ((class my-standard-class) &key options
&allow-other-keys)
(setf (class-local-default-initargs class)
(getf options :default-initargs))
(call-next-method))
(defmethod propagate-class-update ((class my-standard-class)
new-fully-defined-p
old-fully-defined-p
changed-class
&allow-other-keys)
(setf (class-default-initargs class)
(compute-default-initargs class)))
(defun compute-default-initargs (class)
(remove-plist-duplicates
(apply #'append
(mapcar #'class-local-default-initargs
(class-precedence-list class))))
:from-end 't))
∂03-Jun-87 2020 RPG My Message of May 29
To: common-lisp-object-system@SAIL.STANFORD.EDU
In that message I tried to get peoples' attention so that I would make
sure that we did not go too far down the path of something I suspect is an
ad hoc solution to the initialization problem. The point that Gregor
characterizes as something I ``happened to say'' was the main point I was
trying to make - that message was 9 days in the making. In order to get
peoples' attention I used the inflammatory phrasing that solving this
problem in this way would cause me to withdraw my support of CLOS.
Upon reflection, that was a mistake - of course I'm not going to withdraw
my support. I flew off the handle because I think that we have put
together a pretty darn good language with CLOS so far (though it's not
perfect), and I want to make sure we live up to the standards we have set
for ourselves with the work we do to complete it.
It might turn out that Moon's proposed solution is the correct one,
but I want us to explore the alternatives and make sure that there
isn't a whole category of programs we are making hard to write by
not looking at those alternatives now.
You all know that I tend to be outrageous at times, and I do it as part of
the rhetorical game. But I think you all know I've only insisted on one
stupid thing in CLOS so far (the name DEFGENERIC-OPTIONS), so the bluster
cannot mean all that much.
Please accept my apologies and let's get on with the thinking!
-rpg-
∂04-Jun-87 1004 kempf%hplabsc@hplabs.HP.COM SETF- method names
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 4 Jun 87 10:03:40 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 4 Jun 87 10:03:07 pdt
Received: by hplabsc ; Thu, 4 Jun 87 10:02:01 pdt
Date: Thu, 4 Jun 87 10:02:01 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706041702.AA04950@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: SETF- method names
The CLOS spec currently says nothing about what the names of the
SETF- generic functions will be, presumably because the intent
is to encourage use of generalized variable reference. However,
since TRACE and other debugging aids require use of a function
name, lack of an easy handle for SETF- generic function names
(in the current implementation) requires that the user type in
a long, nonstandard name in order to get any debugging information.
Would it be appropriate to say anything about the SETF- generic
function name, realizing that nothing is said about such in CLtL?
Places I could see it being introduced into the spec are:
1) As an additional keyword argument to DEFGENERIC-OPTIONS-SETF,
pg. 2-24:2-25. This could be used to specify the prefix for
generating the SETF- generic function name.
2) As an additional function, like GET-SETF-GENERIC-FUNCTION.
The implementation is simply:
(generic-function-name (get-setf-generic-function <name>))
but would not require the metaobject protocol function GENERIC-FUNCTION-NAME
be used.
jak
∂04-Jun-87 1525 kempf%hplabsc@hplabs.HP.COM Re: object creation / initialization discussion
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 4 Jun 87 15:25:33 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 4 Jun 87 15:25:31 pdt
Received: by hplabsc ; Thu, 4 Jun 87 15:24:22 pdt
Date: Thu, 4 Jun 87 15:24:22 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706042224.AA09308@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: Re: object creation / initialization discussion
I've hesitated to jump into the brouhaha until I had a chance
to review correspondence, and will limit myself to some general
comments, since I think most points of view have been covered.
In particular, I like Dick's analysis, stressing use of features
in the existing CLOS design rather than addition of new, more
complicated features. It does lead to more verbose code for
more complicated applications, thus some applications programmers
will complain, but the simple cases don't require as much conceptual
overhead. The analysis of positional v.s. named arguments in
Common Lisp was interesting. Dick seems to have identified a hole
in the Common Lisp design, which, if correctly filled, could
lead to some simplifications.
His analysis did not touch on order of :INITFORM evaluation, nor
the lexical and dynamic context in which :INITFORM evaluation
occurs. A simple selection of context here would be the lexical
context of the class (as suggested by Danny in an earlier message)
and the dynamic context of one of the methods during MAKE-INSTANCE
invocation. Perhaps the dynamic context could be within MAKE-INSTANCE,
or the ALLOCATE-INSTANCE method, as suggested by Gregor? As for order of
evaluation, perhaps this could be determined by the class precedence
list ordering, for inherited slots, and by lexical ordering within
the DEFCLASS form.
As the 87-002 spec currently stands, the :INITFORM initialization
forms have no reference to previously initialized slots in the
object being initialized, nor can they reference the object being
initialized itself. Dick's proposal seems to imply that the INITIALIZE-INSTANCE
method would be the place for initializations dependent on values
of slots previously initialized to be put. This seems fine with
me. However, I think specifying the order and context of :INITFORM
evaluation is important, for those applications programmers who
feel a need to use side-effects during initialization (however
henious we might find it). If the order and context is not
specified, it will be left up to each implementor to select it,
and thus this aspect of the semantics of initialization will be
determined by the particular implementation rather than the specification.
jak
∂05-Jun-87 2359 Masinter.pa@Xerox.COM Re: object / cleanup subcommittee interaction
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 5 Jun 87 23:59:42 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 05 JUN 87 23:49:40 PDT
Date: 5 Jun 87 23:49 PDT
From: Masinter.pa@Xerox.COM
Subject: Re: object / cleanup subcommittee interaction
In-reply-to: Danny Bobrow <Bobrow.pa>'s message of 2 Jun 87 11:48 PDT
To: common-lisp-object-system@SAIL.STANFORD.EDU
Message-ID: <870605-234940-2970@Xerox>
The cleanup committee is considering proposals for function-type and
non-keyword &Key arguments.
There is no proposal yet submitted for PATHNAME-HASH-TABLE-TYPE-DISTINCT
( making pathname, hash-table separate classes.)
There is no proposal yet submitted for SHARP-COMMA-SPECIAL-FORM.
(load time evaluation function. )
There is no proposal yet submitted for DEFSTRUCT-CLOS.
There is no proposal yet submitted for LEXICAL-ENVIRONMENT-ACCESSORS.
A draft of the proposal format is enclosed. Several proposals were
released last X3J13. Stay tuned to X3J13@Sail.stanford.edu for more
samples...
!
Format for proposals to "clean up" Common Lisp.
Version 10 - 5-Jun-87
Replace the text below in >> double inverted angle-brackets <<. Be
brief; leave testimonials and personal opinions to the discussion at the
end. Be complete; do not expect someone else to fix or redesign parts.
Spell out names (e.g., Masinter rather than LMM) and upcase all Lisp
symbols (DEFUN rather than Defun). I like it better if you write in the
third person rather than first.
Issue: >>A short descriptive label, which starts with a name which
occurs in the index of CLtL, and be a suitable symbol in the Common Lisp
style, e.g., CDR-TERMINATION. .<<
References: >>The pages of CLtL which describe the feature being
discussed, or other references..<<
Category: >>One or more of: CLARIFICATION -- proposal to resolve an
ambiguity or case of under-specified situation in CLtL, where this
ambiguity interferes with portability of code. CHANGE -- proposal for an
incompatible change to the language. ADDITION -- proposal for a
compatible extension to the language. <<
Edit history: >>Author and date of submission (version 1), and author
and date of subsequent versions.<<
Problem description: >>Describe the problem being addressed -- why is
the current situation unclear or unsatisfactory? Avoid describing the
proposal here or arguing for its adoption. <<
Proposal (>>issue-label:proposal-label<<): >> Describe as precisely as
possible what you are proposing. Ideally, this should take the form of
text that could be dropped into CLtL or some new specification document.
If necessary, propose a set of labelled alternatives here, rather than a
single proposal. Each proposal must be a complete design; do not leave
out details. Avoid arguing for the proposal here, just describe it.<<
Test Case: >>When possible, give a sample of Common Lisp code that
illustrates the issue.<<
Rationale: >> A brief argument for the proposal. (If more than one
proposal is listed, discuss each issue separately here and in subsequent
sections.)<<
Current practice: >>Do some/many/no Common Lisp implementations already
work this way? Survey independent Common Lisp implementations -
preferably three or more.<<
Adoption Cost: >>What is the cost to implementors of adopting the
proposal? How much implementation effort is required? Is public-domain
code available? For pervasive changes, can the conversion be
automated?<<
Cost of non-adoption: >>How serious is it if nothing is done? <<
Benefits: >>What is better if the proposal is adopted? How serious is
the problem if just left as it is? <<
Conversion Cost: >>For incompatible changes, what is the cost to users
of converting existing user code? To what extent can the process be
automated? How?<<
Esthetics: >>How does this proposal affect the simplicity of the
language, ease of learning, etc.<<
Discussion: >> Additional arguments, discussions, endorsements,
testimonials, etc. should go here. A blow-by-blow account of debates is
not necessary. <<
∂06-Jun-87 1219 Gregor.pa@Xerox.COM Re: Object creation discussion (at last!)
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 6 Jun 87 12:18:55 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 06 JUN 87 12:18:29 PDT
Date: 6 Jun 87 12:18 PDT
From: Gregor.pa@Xerox.COM
Subject: Re: Object creation discussion (at last!)
In-reply-to: Bobrow.pa's message of 2 Jun 87 18:37 PDT
To: Bobrow.pa@Xerox.COM
cc: Common-Lisp-Object-System@sail.stanford.edu
Message-ID: <870606-121829-3209@Xerox>
Let me take a stab at simplifying part of Danny's message. Danny is
proposing that the entire initialization protocol be defined in a
procedural way, using methods that the user defines on specific generic
functions. In particular, Danny is going one step farther than a couple
of the messages that I sent out in that he is proposing that initarg
defaulting and initarg declaration be done procedurally. Originally, I
was only proposing that initarg specification be done procedurally.
I didn't really like this proposal when I first heard it, but I like it
a lot now after thinking about it for a bit more. This message sketches
out in a bit more detail what it would be like:
initarg DEFAULTING.
There are two generic functions involved. class-default-initargs and
merge-initargs.
CLASS-DEFAULT-INITARGS, returns the default-initargs for a given class.
It is the collection of the initargs for all the superclasses inherited
in the obvious way. The class-default-initargs generic function uses
standard method combination. There are two pre-defined methods on
class-default-initargs, these are as described in a message I sent out
earlier in the week:
(defmethod default-initargs ((c object))
())
(defmethod default-initargs :around ((c object))
(remove-duplicates-from-plist (call-next-method) :from-end 't))
Given these methods, a user can define default initargs for a particular
class using methods like the following (also from my message of last
week):
(defmethod default-initargs ((c menu))
(list* '(:highlighting :invert)
'(:expose-near *default-expose-near*)
(call-next-method)))
(defmethod default-initargs ((c color-menu))
(list* '(:highlighting ':red)
(call-next-method)))
MERGE-INITARGS takes the class, the supplied initargs and the default
initargs. It merges the supplied initargs with the default initargs and
returns a complete set of defaulted initargs with the values from the
default initargs evaluated. This value is all set to be passed to the
initialize-instance and allocate-instance generic functions. The
default implementation of this generic function is something like:
(defmethod merge-initargs ((class object) supplied default)
(let ((total nil))
(do-initargs (name val default)
(unless (getf name supplied)
(push name total)
(push (eval val) total)))
(append supplied (reverse total))))
As I showed in my message of last week, its really easy to optimize all
this to run just as fast as constructors do now, so speed is not an
issue here.
Some of the reasons I like this are:
It builds on existing mechanism, people can understand it without
having to understand new mechanism.
Because it builds on documented, primitive mechanism, people can
tailor it new ways. Specifically, if for a certain class, the presence
of a particular initarg means that several default initargs should not
be included in the merge, it is easy for someone to figure out how to do
that. They just define their own method on merge-initargs which
implements that rule.
initarg DECLARATION is real simple.
There is one pre-defined method on class-legal-initargs
(defmethod class-legal-initargs ((class object))
())
Users define methods like:
(defmethod class-legal-initargs ((class plane))
(list* ':speed ':engines (call-next-method)))
If a user wants to explicity override some initargs provided by a
superclass they can do that since everything is procedural and under
their control:
(defmethod class-legal-initargs ((class boat))
(let ((supers (call-next-method)))
(list* ':speed (remove :color supers))))
∂06-Jun-87 1350 RPG Order of Initialization
To: common-lisp-object-system@SAIL.STANFORD.EDU
I thought that we have already specified that the INITFORMs happen
in the lexical context within which the DEFCLASS occurred. If there are
specials in the INITFORMs, I suppose that the dynamic context in which
the MAKE-INSTANCE is evaluated provides the dynamic context.
In terms of the order of evaluation of the INITFORMs, I thought that
the inheritance rules we had for slot descriptions settled which INITFORM
was evaluated to provide the initial value for the slot.
In terms of the order of evaluation of the INITIALIZE-INSTANCE methods, it
always seemed to me that method combination was how we should control
that, but that the most sensible default order was most general to most
specific (that is, like :AFTER).
There are, of course, problems with my &required-key proposal. One is that
unless there is some way to not pass all of the optional arguments, there
is no way to have a function with both required keyword and truly optional
positional arguments.
Suppose someone writes
(defun f (x y &optional a b &key foo bar baz ola)
(list x y a b foo bar baz ola))
and this form is evaluated:
(f <a1> <a2> <a3> <a4> <a5> <a6> <a7> <a8>)
The binding of the variables in the function definition goes like this:
x is bound to <a1>, y is bound to <a2>, a is bound to <a3>, and b is
bound to <a4>. Now we lift our heads from the sand and look at what
<a5> is. It should be one of :foo, :bar, :baz, or :ola. Now suppose
we had written:
(f 1 2 :foo 4 :bar 5 :baz 6)
Did the user intend for a to be bound to :foo, or did he intend for
a and b to not be supplied?
Here is my proposal for lambda expressions; it includes Moon's
proposal for non-keyword package symbols to be names of arguments:
(lambda ({var}*
[&optional {var | (var [initform [svar]])}*]
[&required-key {name}*]
[&rest var]
[&key {var | (name var)} [initform [svar]])}*
[&allow-other-keys]]
[&aux {var | (var [initform])}*])
{declaration | documentation-string}*
{form}*)
where var, initform, svar are exactly as before, and name is the name of
a keyword argument, which can be a symbol in any package. Parsing an
argument list proceeds as follows:
Let nrp be the number of required positional parameters. The first nrp
supplied arguments are paired with the nrp required positional parameters.
The remaining supplied arguments are scanned left-to-right, starting with
scanning for positional optionals. If a supplied argument is EQ to one of
the required named parameters, the scanning for positional optionals ends
and all unpaired positional optionals are defaulted according to the
lambda-list specification; then named parameter parsing begins. If a
supplied argument is not EQ to any required named parameter, it is paired
with the next positional optional parameter.
Once the scanning for optional positional parameters has ended, scanning
for named parameters begins. Named parameter parsing is as in current
Common Lisp, except that if, at the end, there are unsupplied
required named arguments, an error is signaled.
The difference between this parsing algorithm and the current Common Lisp
one is that the occurrence of the first required named parameter stops
parsing of positional optionals. Therefore, the only way to pass the name
of required named parameter is as a required positional or required named
argument. Also, if optional named arguments appear to the left of all
required named arguments, they can be taken as positional optionals.
Examples:
(defun f (x y &optional a b &required-key :foo :bar &key baz ola)
(list x y a b foo bar baz ola))
(f 1 2 3 4 :foo 5 :bar 6 :baz 7 :ola 8)
=> (1 2 3 4 5 6 7 8)
(f 1 2 3 :bar 4 :baz 5 :foo 6 :ola 7)
=> (1 2 3 nil 6 4 5 7)
(f 1 2 :baz 3 :foo 4 :bar 5)
=> (1 2 :baz 3 4 5 nil nil)
(f 1 2 :baz :foo 3 :bar 4)
=> (1 2 :baz nil 3 4 nil nil)
Because of Moon's proposal to not require keywords to be in the keyword
package, this proposal introduces some ugliness, but it uses the well-used
design principle: feel free to introduce ugliness and inconsistency for
new users in order to keep old code working.
-rpg-
∂06-Jun-87 1624 kempf%hplabsc@hplabs.HP.COM Re: Order of Initialization
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 6 Jun 87 16:24:20 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Sat, 6 Jun 87 14:27:50 pdt
Received: by hplabsc ; Sat, 6 Jun 87 14:26:48 pdt
Date: Sat, 6 Jun 87 14:26:48 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706062126.AA01592@hplabsc>
To: RPG@SAIL.STANFORD.EDU, common-lisp-object-system@SAIL.STANFORD.EDU
Subject: Re: Order of Initialization
>
>I thought that we have already specified that the INITFORMs happen
>in the lexical context within which the DEFCLASS occurred. If there are
>specials in the INITFORMs, I suppose that the dynamic context in which
>the MAKE-INSTANCE is evaluated provides the dynamic context.
>
This sounds fine with me. I didn't remember a decision being reached
on the lexical part. The dynamic context of MAKE-INSTANCE is OK, presumably
just before the INITIALIZE-INSTANCE method is called and just after
ALLOCATE-INSTANCE? Otherwise, either the instance doesn't yet exist,
or the user could have done some potential customized initialization
which would be overwritten.
>In terms of the order of evaluation of the INITFORMs, I thought that
>the inheritance rules we had for slot descriptions settled which INITFORM
>was evaluated to provide the initial value for the slot.
My reading of the 87-002 document is that the initialization form
which is run for a particular slot is the first one which is encountered,
searching up the class precedence list. This says nothing, however, about
the order in which the initialization forms for all the slots are run.
This is what I meant. I would suggest that the lexical ordering of
slots within a class determine the order in which the initialization
forms are run for the slots defined by that class, and that the
order of the class precedence list determine the order for the entire
instance.
>In terms of the order of evaluation of the INITIALIZE-INSTANCE methods, it
>always seemed to me that method combination was how we should control
>that, but that the most sensible default order was most general to most
>specific (that is, like :AFTER).
In fact, the rules for method combination and initialization on
pg. 1-21:1-25 could determine this. I can't see any reason to
special case INITIALIZE-INSTANCE.
I'll postpone comments on the &REQUIRED-KEY proposal and Gregor's
proposal for a functional interface to initialization until I've
had a chance to study them.
jak
∂06-Jun-87 1636 RPG Order of Initialization
To: Common-lisp-object-system@SAIL.STANFORD.EDU
Jak sez:
``This says nothing, however, about the order in which the initialization
forms for all the slots are run.''
I respond:
This say everything about how stupid I am when I read messages about CLOS.
The two choices must be some ordering depending on the textual order
within a DEFCLASS and on the CPL for inherited slots, or else it is
an error to depend on it.
-rpg-
∂08-Jun-87 1907 Bobrow.pa@Xerox.COM Open Issues in 87-002
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 8 Jun 87 19:07:03 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 08 JUN 87 18:38:46 PDT
Date: 8 Jun 87 18:38 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Open Issues in 87-002
To: common-lisp-object-system@SAIL.STANFORD.EDU
Message-ID: <870608-183846-1250@Xerox>
I was reading over the spec the last few days, and have found the
following open issues that need to be resolved (or issues that I would
like to open). Comments please.
p1-12 Should defclass be allowed to change the metaclass of an existing
class? Under what conditions should a subclass of standard-class have
the same properties wrt instance updating as standard class? Gregor,
what is the answer in PCL right now?
p1-13 What is the initial class hierarchy in CLOS? I recall a message
by Sonya implying she was working on capturing our agreement at Ricky's.
Is there a rewritten section on this?
p1-17 "It is currently under discussion whether to provide constructs
for giving generic functions local names." Do we want to have this
discussion, or to punt on this syntax. I recall we did come up with some
reasonble semantics for a GFLET and GFLABELS.
p1-18 It is not specified whether get-setf-generic-function is a
setf-able form. I suggest that it be made so. This would allow one to
trace setf-generic-function's without having to know their names.
p1-19 "... Common Lisp be modified to include the following semantics
for quote in a type specifier:
(deftype quote (object) '(member ,object)))"
Has any proposal for this been given to the cleanup committee?
p1-24 Sshould we have a call-next-method? which calls such a next method
if it exists, else returns nil (rather than signalling an error?). This
seems useful rather than having to define many base methods on object.
p1-20 Reference to type system correspondence to class system.
------
p2-3 Functions underlying the commonly used macros is neither complete
nor correct. The generic-functions add-method, get-method,
get-setf-generic-function, and remove-method should be in the
metaobjects chapter. make-method (p45)and make-generic-function (p42)
should be removed as soon as we have the initialization protocol set.
p2-6 I think we have reached agreement on the extension to
call-next-method to take arguments. Do I hear a volunteer to write up
this page.
2-13(?) The generic function class-name is not written up. It returns a
name for the class as argument. I believe that (class-name class)
should be setf-able. Can a class have more than one name? Should
class-name then return a second argument -- the rest of the names this
class is known by.
Comments?
p2-16 We have agreed that we don't yet know whether the :constructor
option should be part of defclass.
p2-19 Values: I thought we agreed that all top level forms should return
the object. It says here "returns the name of the class"
p2-22 Same comment as 2-19
p2-26 I believe that short form method combination ought to be a macro
in the standard library, and documented there, not in the basic
principles. I think the standard combinations :append, :and, :or, ...
should also be put in the standard library too.
p2-35 The argument order of the setf method ought to be documented here.
Gregor proposed that new-value be the first argument. Any problem with
this?
p2-39 Arguments: "list of t's" should be replaced by "list of classes
named t" since get-method only takes specializers, not names of
specializers.
p2-40 Should be specified that get-setf-generic-function is set-able
(see 1-18
p2-44 INITIALIZATION PROTOCOL for make-instance.
p2-46 Last line: If call-next method is extended ..." I see no reason
for additional keyword arguments.
p2-51 print-object should take a depth argument.
p2-54 slot-missing should be documented
∂09-Jun-87 0719 skeene@STONY-BROOK.SCRC.Symbolics.COM Open Issues in 87-002
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 9 Jun 87 07:19:39 PDT
Received: from JUNCO.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 168008; Tue 9-Jun-87 10:18:45 EDT
Date: Tue, 9 Jun 87 10:18 EDT
From: Sonya E. Keene <skeene@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Open Issues in 87-002
To: Bobrow.pa@Xerox.COM
cc: common-lisp-object-system@SAIL.STANFORD.EDU
In-Reply-To: <870608-183846-1250@Xerox>
Message-ID: <870609101827.6.SKEENE@JUNCO.SCRC.Symbolics.COM>
Line-fold: No
Date: 8 Jun 87 18:38 PDT
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
I was reading over the spec the last few days, and have found the
following open issues that need to be resolved (or issues that I would
like to open). Comments please.
p1-13 What is the initial class hierarchy in CLOS? I recall a message
by Sonya implying she was working on capturing our agreement at Ricky's.
Is there a rewritten section on this?
It's almost done. I'll finish it up this week and send it to the list.
∂09-Jun-87 0803 kempf%hplabsc@hplabs.HP.COM I. Formal Specification of Gen. Fcn. Invocation
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 08:03:35 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Tue, 9 Jun 87 08:03:22 pdt
Received: by hplabsc ; Tue, 9 Jun 87 08:02:18 pdt
Date: Tue, 9 Jun 87 08:02:18 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706091502.AA00446@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: I. Formal Specification of Gen. Fcn. Invocation
For some time now, I have been somewhat bothered by the lack of
precision in the 87-002 specification of method invocation. While
the rest of the document (particularly the inheritance algorithm)
is fairly precisely worded, the section of Part 1 on method combination
and calculation of the effective method is fairly loose and informal.
Until recently, I've been involved in getting an attractively performing
prototype of CLOS up for our internal applications developers, and
so have not had any time to look at the issue in any detail. However,
having reached a checkpoint in that effort, I decided to revisit the
issue and attempt a formal specification of method invocation and
combination.
I will post the results in a series of three notes which deal with
the three aspects of calculating the effective method:
1) Determining the set of applicable methods,
2) Sorting the set of applicable methods by precedence order,
3) Calculating the effective method from the sorted set of
applicable methods.
I would hope that one of the committee members with interest and
inclination would check through the specification and offer any
corrections or additions, and that the 87-002 document could be
amended to include the result. If amending the document turns out
to be not possible, perhaps some other medium could be found for
presenting the result.
As an "executive summary", here is a short overview of the result:
1) Only one major inconsistency was found in the specification.
The requirement at the bottom of pg. 1-24 that the invocation of
CALL-NEXT-METHOD in the least specific :AROUND method would return
the effective method invocation result to the continuation (caller)
requires that CALL-NEXT-METHOD in the least specific :AROUND method
behave fundamentally differently than in other instances. It also
contradicts the statement in the middle of the page that the
most specific :AROUND method provides the value for the invocation.
I suspect it is a typo, and would suggest that the statement in
the middle of the page prevail.
2) The case of having two EQL specializers on the same parameter
which differ during sorting of applicable methods cannot occur.
It is forbidden by the way in which the set of applicable methods
is constructed. An ambiguous statement in the second paragraph at
the top of pg. 1-22 implies that it can, however.
3) The least formal aspect of this specification is Part 3).
I think that some form of temporal logic would be needed to
do this correctly (I may be wrong, however), and so, rather
than go to that machinery, I simply made some general observations
and reasoned somewhat informally. Ultimately, it might be worth
doing the exercise.
Walter Olthoff, in our lab, has done some preliminary work to
cast the specification into the Axis executable formal specification
language, and we may continue this effort as an additional check
on accuracy.
I've also made some initial notes on an application of how this
specification could be used (for anyone who thinks its a waste
of time). In particular, it is possible to derive conditions on
the actual parameters which limit changes in the set of applicable
methods, changes in the sorted list of applicable methods, or both,
it arguments are allowed for CALL-NEXT-METHOD. These conditions
may be useful in construction compile time optimizations, for example.
Finally, the restriction to standard character sets has required
the use of bizarre (for formal methods) notation. For this, I
apologize. One of these days e-mail will support enough bandwith
that we can send around bitmaps.
jak
∂09-Jun-87 0804 kempf%hplabsc@hplabs.HP.COM II. Formal Specification of Gen. Fcn. Invocation
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 08:03:59 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Tue, 9 Jun 87 08:03:55 pdt
Received: by hplabsc ; Tue, 9 Jun 87 08:02:47 pdt
Date: Tue, 9 Jun 87 08:02:47 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706091502.AA00451@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: II. Formal Specification of Gen. Fcn. Invocation
Formation of the Set of Applicable Methods
Given, a generic function invocation:
(gf a(1) a(2) a(3) ... a(n) )
where:
gf = generic function name
a(j) = jth actual parameter
Let:
A = { a(j) }, j=1 ... n
M = { m(i) | m(i) is a method function for gf}
m = number of required parameters for gf
We seek to form the set of applicable methods, MA. The 87-002
wording about how this is done is rather vague:
Given a generic function and a set of arguments, the
applicable methods are all methods for that generic
function whose parameter specializers are satisfied
by their corresponding arguments.
A suggested rewording, which would tighten up the specification
is:
Given a generic function invocation, the applicable
methods are all methods all of whose formal parameter
specializers satisfy Relationship R with respect to
the corresponding actual parameters.
We now define Relationship R.
Let:
F(i)={ f(j) | f(j) is a formal parameter specializer for m(i) }
1 <= j <= m
Note that the F(i) are ordered sets, whose elements match one for one
with the elements of A. In cases where there are more required parameters
than specialized parameters, we extend F(i) using T as the specializer,
indicating that any actual parameter will match the formal parameter
specializer.
Define c(j) as the class of actual parameter a(j). With apologies
to Knuth, define Algorithm I as the algorithm used to calculate
the class precedence list for c(j), and cpl(j) as the result of
applying Algorithm I to c(j). Since the class precedence list is
a totally ordered set, we can define the index operator to return
the index of c(l) in the class precedence list:
index: class-object x cpl -> nat* (* is needed for error case)
This operation will be needed during sorting.
The following predicates map elements of f(j) into booleans:
eql-specializer-p = true if f(j) is a quoted object
false otherwise
class-specializer-p = true if f(j) is a class object
false otherwise
Relationship R is satisfied for one of the F(i) if and ony if, for
all (f(j), a(j) ), j = 1 ... n, either:
eql-specializer-p(f(j)) AND a(j) = f(j)
OR
class-specializer-p(f(j)) AND f(j) element cpl(j)
We denote the set of applicable methods as MA, and go on to
specifying the sorting algorithm.
jak
∂09-Jun-87 0804 kempf%hplabsc@hplabs.HP.COM III. Formal Specification of Gen. Fcn. Invocation
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 08:04:29 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Tue, 9 Jun 87 08:04:28 pdt
Received: by hplabsc ; Tue, 9 Jun 87 08:03:24 pdt
Date: Tue, 9 Jun 87 08:03:24 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706091503.AA00467@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: III. Formal Specification of Gen. Fcn. Invocation
Sorting the Set of Applicable Methods
Let:
MA = { ma(i) | ma(i) is an applicable method }
F(i) = { f(j) | f(j) is a formal parameter specializer for ma(i) }
Define the predicate
class-equal-p: class-object x class-object -> boolean
as:
class-equalp(f(l),f(m)) = true if f(l) and f(m) represent
the "same" class
false otherwise
We assume that the F(i) are totally ordered, with the ordering determined
by the :ARGUMENT-PRECEDENCE-ORDER for the generic function (default
being left to right).
Taking the F(i) pairwise, we define the equivalence relationship
"qualifier equal" (denoted =(q) ) on the corresponding ma(i)
as follows.
Let f(i,k) and f(j,k) be the kth elements from F(i) and F(j), respectively.
Then ma(i) =(q) ma(j) if and only if:
( eql-specializer-p(f(i,k)) AND eql-specializer-p(f(j,k))
AND f(i,k) = f(j,k)
)
OR
( class-specializer-p(f(i,k)) AND class-specializer-p(f(j,k))
AND class-equal-p(f(i,k),f(j,k))
)
for all (f(i,k),f(j,k)), k = 1 ... n
Note that =(q) groups the ma(i) into equivalence classes, with the
members of an equivalence class being distinguishable only by virtue
of their method qualifiers.
Let MAQ be the set of equivalence classes formed by applying =(q)
to MA. We impose a total ordering on MAQ by the following procedure.
For all maq(i), maq(j), i != j, select an ma(i) and ma(j) and
let F(i) and F(j) be the respective sets of ordered formal parameter
specializers.
Since ma(i) and ma(j) are from different equivalence classes,
there will a least k, 1 <= k <= n, for which the f(.,k) are
not equal, with the f(.,k) being ordered with respect to the ordering
imposed by the generic function.
For that k, let cpl(k) be the class precedence list for the
class c(k) of the matching formal parameter a(k). Define the
following predicate:
cpl-precedes-p: class-object x class-object x cpl -> boolean
as:
cpl-precedes-p(c(l),c(m),cpl) = true if index(c(l),cpl) <=
index(c(m),cpl)
false otherwise
We say that maq(i) is more specific than maq(j)
(written maq(i) <(p) maq(j) ) if and only if one of the following
is true:
1) eql-specializer-p(f(i,k))
2) class-specializer-p(f(i,k)) AND (NOT (eql-specializer-p(f(j,k)))
AND cpl-precedes-p(f(i,k),f(j,k),cpl(k))
Otherwise maq(j) <(p) maq(i).
Note that we need not even consider the case in which:
eql-specializer(f(i,k)) AND eql-specializer(f(j,k))
since construction of the set of applicable methods assures that
f(i,k) = f(j,k) if this true, in which case ma(i) and ma(j) would
be in the same equivalence class, or would not differ on specializer
k.
We denote the totally ordered set of qualifier equivalence classes
as MAQS and go on to specify the calculation of the effective
method.
jak
∂09-Jun-87 0805 kempf%hplabsc@hplabs.HP.COM IV. Formal Specification of Gen. Fcn. Invocation
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 08:05:04 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Tue, 9 Jun 87 08:04:50 pdt
Received: by hplabsc ; Tue, 9 Jun 87 08:03:47 pdt
Date: Tue, 9 Jun 87 08:03:47 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706091503.AA00472@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: IV. Formal Specification of Gen. Fcn. Invocation
Calculation of the Effective Method
Given the totally ordered set of method equivalence classes, MAQS,
the effective method (what actually gets executed) needs to be
formed.
In the general case, nothing can be said formally about how to
calculate the effective method, because the metaclass function
COMPUTE-EFFECTIVE-METHOD can return any Lisp form, if user
defined method combination is applicable.
We therefore restrict consideration to standard method combination.
We now need to break down the equivalence classes in MAQS and
sort out the methods based on their qualifiers.
From the sorting calculation, we remember that two applicable methods
are qualifier equivalent (written =(q)) if they are the same, except
for their method qualifiers. Applicable methods which are =(q) form
equivalence classes, which are sorted by precedence order, with
the precedence order being designated by <(p).
Define the following predicates:
primary-p: method -> boolean
primary-p(m) = true if m is an unqualified (primary) method
false otherwise
around-p: method -> boolean
around-p(m) = true if m is an :AROUND qualifed method
false otherwise
before-p: method -> boolean
before-p(m) = true if m is a :BEFORE qualified method
false otherwise
after-p: method -> boolean
after-p(m) = true if m is a :AFTER qualified method
false otherwise
Note that restriction to standard method combination means that
the following:
NOT (primary-p(ma(i)) OR around-p(ma(i)) OR before-p(ma(i))
OR after-p(ma(i))
)
cannot occur, for ma(i) element of MA, the set of applicable methods.
Given an ma(i), let the function:
preceedes-p: method x method x sorted-=(q)-set -> boolean
take two methods and the sorted set of =(q) equivalence classes
and return true if the equivalence class of the first argument is
more specific than that of the second.
Form the following four sets:
MR = { ma(i) | ma(i) element MA AND around-p(ma(i)) AND
preceeds-p(ma(i),ma(j),MAQS) if i < j
}
MP = { ma(i) | ma(i) element MA AND primary-p(ma(i)) AND
preceeds-p(ma(i),ma(j),MAQS) if i < j
}
MB = { ma(i) | ma(i) element MA AND before-p(ma(i)) AND
preceeds-p(ma(i),ma(j),MAQS) if i < j
}
MF = { ma(i) | ma(i) element MA AND after-p(ma(i)) AND
preceeds-p(ma(i),ma(j),MAQS) if i < j
}
Specification of standard method combination requires that the
execution sequence for the four sets be ordered as follows:
MR -> MB -> MP -> MF -> {mr(1) | mr(m), m = cardinality(MR) }
Complete execution of MB and MF is guaranteed, if either MR = {}
or mr(m) calls CALL-NEXT-METHOD, so transferring control to mb(1).
In general, unless the method body is coded otherwise, only mr(1)
need be completely executed. However, mp(1) must exist (even if
it is not executed) or an error occurs. (Aside: was this the
intended behavior? It seems to me that making control transfer
from the :AROUND method to the primary method dependent on
whether or not the user codes the least specific :AROUND method
with a CALL-NEXT-METHOD makes the :AROUND method more like a
primary, in the qualitative sense.)
The end sequence of effective method execution is ambiguously
specified. The middle of pg. 1-24 implies that, given MR exists,
then the return value is determined by mr(1), the most specific
:AROUND method, while the bottom of the page implies that,
given a sequence of execution transfers occurs in which execution
leaves MR through the least specific method (mr(m), m = cardinality(MR)),
then control transfers back to the calling continuation
for the entire generic function invocation, rather than
through return of the CALL-NEXT-METHODs to mr(1). I believe this is a typo.
As a solution, I would suggest that CALL-NEXT-METHOD in mr(m) behave
exactly the same as in other cases. The "next" method in this case
would be one of mb(1) (the first :BEFORE method) or mp(1) (the first
primary), depending on whether or not MB = {} (i.e., if there are
any :BEFORE methods). When CALL-NEXT-METHOD returns, control returns
to mr(m-1), and, eventually, to mr(1), which then controls the return
value.
In any event, control transfer from MR to MB can occur only via
a CALL-NEXT-METHOD in mr(m). Once control transfer to MB has occured,
MB is fully executed, then (at least) mp(1) and any other mp(j) via
CALL-NEXT-METHOD. After execution of the MP, MF is fully executed,
and control returns to mp(m). Depending on whether you believe
the middle or bottom of 1-24, mp(m) either returns the primary
value directly to the generic function calling continuation,
or the CALL-NEXT-METHOD in mp(m) returns the value
to its continuation, etc., until mp(1) is reached,
where the value is returned to the gf's continuation.
Additional rules on pg. 1-25 spell out where CALL-NEXT-METHOD can
be used, and the logic behind standard method combination.
jak
∂09-Jun-87 0854 kempf%hplabsc@hplabs.HP.COM Re: Order of Initialization
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 08:54:10 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Tue, 9 Jun 87 08:53:45 pdt
Received: by hplabsc ; Tue, 9 Jun 87 08:52:15 pdt
Date: Tue, 9 Jun 87 08:52:15 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706091552.AA01177@hplabsc>
To: Common-lisp-object-system@SAIL.STANFORD.EDU, RPG@SAIL.STANFORD.EDU
Subject: Re: Order of Initialization
>Jak sez:
>
>``This says nothing, however, about the order in which the initialization
>forms for all the slots are run.''
>
>I respond:
>
>This say everything about how stupid I am when I read messages about CLOS.
>
It's difficult to maintain continuity in a discussion when the lag in
a reply is a day. Not your fault.
>The two choices must be some ordering depending on the textual order
>within a DEFCLASS and on the CPL for inherited slots, or else it is
>an error to depend on it.
>
>
As I see it, Common Lisp does one of three things when the order of
evaluation matters:
1) Specifies the order, as is the case with the order of evaluation
of function arguments, or PROGN,
2) Gives the programmer a construct in which the order is specified
and one in which it is not, as in LET and LET*.
3) Does not specify in what order evaluation occurs. DEFSTRUCT is
in this category (except for the statement that initialization
forms are evaluated in the lexical context of the DEFSTRUCT
definition). This would leave it up to the implementation.
I think 1) should be the case. This avoids making it implementation
dependent (case 3) and avoids having to introduce extra syntatic
machinery (case 2).
jak
∂09-Jun-87 0934 kempf%hplabsc@hplabs.HP.COM Re: Open Issues in 87-002
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 09:33:42 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Tue, 9 Jun 87 09:33:41 pdt
Received: by hplabsc ; Tue, 9 Jun 87 09:32:24 pdt
Date: Tue, 9 Jun 87 09:32:24 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706091632.AA02166@hplabsc>
To: Bobrow.pa@Xerox.COM, common-lisp-object-system@SAIL.STANFORD.EDU
Subject: Re: Open Issues in 87-002
Some opinions on the open issues note which Danny posted.
>p1-12 Should defclass be allowed to change the metaclass of an existing
>class?
I think DEFCLASS shouldn't be allowed to change the metaclass, since
the representation for instances of classes with the two different
metaclasses might be radically different.
>p1-17 "It is currently under discussion whether to provide constructs
>for giving generic functions local names." Do we want to have this
>discussion, or to punt on this syntax. I recall we did come up with some
>reasonble semantics for a GFLET and GFLABELS.
There have been a couple times when I've thought this would be handy.
On the other hand, we may ultimately be accused of junking up the
standard with things that some people don't need. On the presumption
that someone will accuse us of that anyway, it would probably be a good idea
to look into this. I believe there was some discussion of a GLAMBDA
in addition? Perhaps this functionality could be achieved by providing
a GFUNCTION special form (like the FUNCTION special form), which takes
a list of lambda expressions and produces a generic function object.
I suppose we'll need a reader macro for this as well, like #'.
Arguments for these constructs are that it integrates generic functions
more smoothly into the language. Arguments against are that generic
functions are a higher level modularity mechanism than functions. My
opinion is that the former is probably more relevant, since the package
system is really the fundamental modularity mechanism for organizing
medium scale structure in Common Lisp.
>p1-18 It is not specified whether get-setf-generic-function is a
>setf-able form. I suggest that it be made so. This would allow one to
>trace setf-generic-function's without having to know their names.
I vote yes on this one. We are already having trouble tracing
SETF- generic functions, and need some kind of handle.
>p1-24 Sshould we have a call-next-method? which calls such a next method
>if it exists, else returns nil (rather than signalling an error?). This
>seems useful rather than having to define many base methods on object.
I think this would be a good idea, however, we need to consider the
performance tradeoff. If CALL-NEXT-METHOD is viewed as a means of
modifying the flow of control in the effective method, rather than
a fast way of invoking the next least specific method, I think this
would be useful (although a compiler would be free to optimize, if
it so chooses). In the most general case, the conditions determining
whether the set of applicable methods are still valid would need
to be re-checked on each invocation of CALL-NEXT-METHOD with parameters.
>p2-3 Functions underlying the commonly used macros is neither complete
>nor correct. The generic-functions add-method, get-method,
>get-setf-generic-function, and remove-method should be in the
>metaobjects chapter. make-method (p45)and make-generic-function (p42)
>should be removed as soon as we have the initialization protocol set.
Yes. Do people feel the initialization issues are well enough
understood that a proposed addition can be generated in Boston?
>p2-6 I think we have reached agreement on the extension to
>call-next-method to take arguments. Do I hear a volunteer to write up
>this page.
I'll do it, if nobody objects. I won't be able to do it by Boston,
however.
>2-13(?) The generic function class-name is not written up. It returns a
>name for the class as argument. I believe that (class-name class)
>should be setf-able. Can a class have more than one name? Should
>class-name then return a second argument -- the rest of the names this
>class is known by.
I think the class name should be changable, I don't think it should
have more than one name (at least, not for the default metaclass).
But I'm open to hearing some discussion on it, if anybody has any
ideas why it should be done.
>p2-19 Values: I thought we agreed that all top level forms should return
>the object. It says here "returns the name of the class"
This sounds like a typo. It should return the class object.
>p2-22 Same comment as 2-19
Ibid.
>p2-26 I believe that short form method combination ought to be a macro
>in the standard library, and documented there, not in the basic
>principles. I think the standard combinations :append, :and, :or, ...
>should also be put in the standard library too.
I agree.
>p2-35 The argument order of the setf method ought to be documented here.
>Gregor proposed that new-value be the first argument. Any problem with
>this?
I've gotten some complaints from my users that they would rather see
it as the second argument, and also the second argument to the
SETF- generic function. Personally, I don't particularly care, but
I thought I'd just pass this along.
>p2-44 INITIALIZATION PROTOCOL for make-instance.
Yes, this needs to be resolved.
>p2-51 print-object should take a depth argument.
Yes, this is needed. I think we need to maintain some compatibility
with DEFSTRUCT on this.
∂09-Jun-87 1008 kahn.pa@Xerox.COM Re: Open Issues in 87-002
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 10:08:17 PDT
Received: from Salvador.ms by ArpaGateway.ms ; 09 JUN 87 10:07:51 PDT
Date: Tue, 9 Jun 87 10:07:35 PDT
From: Ken Kahn <Kahn.pa@Xerox.COM>
Subject: Re: Open Issues in 87-002
In-Reply-To: <870608-183846-1250@Xerox>
To: Danny Bobrow <Bobrow.pa@Xerox.COM>
cc: common-lisp-object-system@SAIL.STANFORD.EDU
Message-ID: <870609-100751-1086@Xerox>
> p1-18 It is not specified whether get-setf-generic-function is a
setf-able
> form. I suggest that it be made so. This would allow one to trace
setf-generic-function's
> without having to know their names.
Maybe I'm confused, but how would it help tracing unless one re-compiled
all the setf's using the generic function? And how is the problem of
tracing setf's in CLOS any different than the general Common Lisp
problem?
References
Bobrow's message of Mon, 8 Jun 87 18:38:00 PDT -- Open Issues in 87-002
∂09-Jun-87 1035 Bobrow.pa@Xerox.COM Re: Open Issues in 87-002
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 10:35:13 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 09 JUN 87 10:33:13 PDT
Date: 9 Jun 87 10:33 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Open Issues in 87-002
In-reply-to: Ken Kahn <Kahn.pa>'s message of Tue, 9 Jun 87 10:07:35 PDT
To: Kahn.pa@Xerox.COM
cc: Bobrow.pa@Xerox.COM, common-lisp-object-system@SAIL.STANFORD.EDU
Message-ID: <870609-103313-1143@Xerox>
>p1-18 It is not specified whether get-setf-generic-function
>is a setf-able form. I suggest that it be made so. This would
>allow one to trace setf-generic-function's without having to
>know their names.
Maybe I'm confused, but how would it help tracing unless one
re-compiled all the setf's using the generic function? And how is
the problem of tracing setf's in CLOS any different than the
general Common Lisp problem?
This is the same problem as tracing setf's of functions in CommonLisp.
But we have no two argument defsetf. Will someone who knows tell us how
that is done in some Common Lisps.
danny
∂09-Jun-87 1050 kempf%hplabsc@hplabs.HP.COM Re: Open Issues in 87-002
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 10:48:58 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Tue, 9 Jun 87 10:48:36 pdt
Received: by hplabsc ; Tue, 9 Jun 87 10:47:25 pdt
Date: Tue, 9 Jun 87 10:47:25 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706091747.AA03141@hplabsc>
To: Bobrow.pa@Xerox.COM, Kahn.pa@Xerox.COM
Subject: Re: Open Issues in 87-002
Cc: common-lisp-object-system@SAIL.STANFORD.EDU
Here's how I do it:
(macroexpand '(setf <form> b))
then take whatever the name is from the macroexpansion. Turns out
that the names for things like SVREF are mostly well behaved
(LISP::SETF-SVREF) so I can guess most of the time in our Lisp.
This may be an issue for the cleanup committee (perhaps they are
already looking at it?).
jak
∂09-Jun-87 1104 Bobrow.pa@Xerox.COM Re: Order of Initialization
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 11:03:59 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 09 JUN 87 10:55:03 PDT
Date: 9 Jun 87 10:54 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Order of Initialization
In-reply-to: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>'s message of Tue, 9
Jun 87 08:52:15 pdt
To: kempf%hplabsc@hplabs.HP.COM
cc: Common-lisp-object-system@SAIL.STANFORD.EDU, RPG@SAIL.STANFORD.EDU
Message-ID: <870609-105503-1199@Xerox>
jak says
As I see it, Common Lisp does one of three things when the
order of evaluation matters:
1) Specifies the order, as is the case with the order of
evaluation of function arguments, or PROGN,
2) Gives the programmer a construct in which the order is
specified and one in which it is not, as in LET and LET*.
3) Does not specify in what order evaluation occurs. DEFSTRUCT
is in this category (except for the statement that initialization
forms are evaluated in the lexical context of the DEFSTRUCT
definition). This would leave it up to the implementation.
I think 1) should be the case. This avoids making it
implementation dependent (case 3) and avoids having to introduce
extra syntatic machinery (case 2).
I think one should not depend on the order. Consider the ambiguity
resulting from two class definitions:
(defclass c1 ()
((x :initform (initx1))
(y :initform (inity))))
(declass c2 (c1)
((x :initform (initx2)))
These can be in a file in either order. Which order for eveluation of
(initx2) and (inity) do you think is correct. I can think of arguments
for both. Further, consider
(defclass c3 (c1)
((z :initform (initz))
(y :initform (inity2))
(x :initform (initx3))))
So my choice is 3, the user should not depend on the order.
danny
∂09-Jun-87 1136 Bobrow.pa@Xerox.COM Re: I. Formal Specification of Gen. Fcn. Invocation
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 11:36:41 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 09 JUN 87 11:35:01 PDT
Date: 9 Jun 87 11:34 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: I. Formal Specification of Gen. Fcn. Invocation
In-reply-to: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>'s message of Tue, 9
Jun 87 08:02:18 pdt
To: kempf%hplabsc@hplabs.HP.COM
cc: common-lisp-object-system@sail.stanford.edu
Message-ID: <870609-113501-1274@Xerox>
1) Only one major inconsistency was found in the specification.
The requirement at the bottom of pg. 1-24 that the invocation of
CALL-NEXT-METHOD in the least specific :AROUND method would return
the effective method invocation result to the continuation (caller)
requires that CALL-NEXT-METHOD in the least specific :AROUND method
behave fundamentally differently than in other instances. It also
contradicts the statement in the middle of the page that the most
specific :AROUND method provides the value for the invocation. I
suspect it is a typo, and would suggest that the statement in the
middle of the page prevail.
You must have a different reading of the words than I do. In the middle
of the page it says:
* If there are any :around methods, the most specific :around method is
called. It supplies the value for the method.
At the bottom it uses the phrase "If no :around methods were invoked"
This means that there are no :around methods. In this case, the value
is the value returned from what I will call the "effective primary
method" which will be the value returned by the most specific primary
method. The "effective primary method" is the method constructed
approximately as
(PROG2 (PROGN before1 .. beforen) primary1 (PROGN aftern ... after1))
where index 1 is more specific method than one with 2, ...
call-next-method always works on a list of effective methods, and always
calls the next in the list. The list for standard method combination is
(around1 ... aroundn effective-primary-method)
and hence there is no difference in what call-next-method does in the
two cases. The value is of course the value of the first method on this
list. I am not sure I understand your statement:
" the invocation of CALL-NEXT-METHOD in the least specific
:AROUND method would return the effective method invocation result
to the continuation (caller)"
Further in your formal description, you talk about control passing to
the before methods, without building a construct like
effective-primary-method. I think this is a mistake, since it loses the
nesting of the methods, and how values are returned.
-----
2) The case of having two EQL specializers on the same
parameter which differ during sorting of applicable methods cannot
occur.
I read the statement on page 1-22 as a proof of this statement.
∂09-Jun-87 1743 @RELAY.CS.NET:DUSSUD%Jenner@TI-CSL.CSNET Re: Object creation discussion (at last!)
Received: from RELAY.CS.NET by SAIL.STANFORD.EDU with TCP; 9 Jun 87 17:43:30 PDT
Received: from relay2.cs.net by RELAY.CS.NET id ac03830; 9 Jun 87 20:24 EDT
Received: from ti-csl by RELAY.CS.NET id ag02593; 9 Jun 87 20:18 EDT
Received: by tilde id AA10877; Tue, 9 Jun 87 16:47:43 CDT
Message-Id: <2759261775-6137078@Jenner>
Date: Tue, 9 Jun 87 16:36:15 CDT
From: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
To: Bobrow.pa@XEROX.COM
Cc: Common-Lisp-Object-System@SAIL.STANFORD.EDU
Subject: Re: Object creation discussion (at last!)
In-Reply-To: Msg of 2 Jun 87 18:37 PDT from Bobrow.pa@xerox.com
My message has two parts, the first one is about specifics and the
second one is about the general instance creation problem.
Part I:
I am trying to comment on the Gregor/Bobrow proposal as I see it after pasting
all the parts together:
from Bobrow:
(defmethod make-instance ((c standard-class) &rest initargs)
(let ((o (allocate-instance c)))
;o is an object with slots filled in by :initforms
(apply #'initialize-instance o (initial-args o initargs))
o)
This is not enough, we need to be able to pass initargs to allocate-instance as
well.
Thus I think I would rewrite this (using Gregor's part):
(defmethod make-instance ((c standard-class) &rest initargs)
(let* ((init-args (merge-initargs initargs (default-initargs c)))
(o (apply #'allocate-instance c init-args)))
;o is an object with slots filled in by :initforms
(apply #'initialize-instance o (initial-args o initargs))
o))
Is this correct?
Now, who checks the legality of init-args? It seems it would be merge-initargs.
One thing I am not thrilled about with this proposal is that the legality check,
the defaulting and the merging of the initargs are done in three places. Here
is an example of what I don't like:
If a user wants to explicity override some initargs provided by a
superclass they can do that since everything is procedural and under
their control:
(defmethod class-legal-initargs ((class boat))
(let ((supers (call-next-method)))
(list* ':speed (remove :color supers))))
Now, if default-initargs is left to its usual form, it gets out of sync. We can
produce a default-init-args plist that would contain non legal initargs.
Part II:
Thinking about instance creation, it seems that we have a three
dimensional problem and we try to solve it using two dimensional
projections:
The first dimension is the class hierarchy.
The second is the initargs dimension.
the third is the operations dimension (legality check, defaulting,
side-effect).
Bobrow/Gregor tries to project the problem along the operation dimension,
thus losing the ability to do all the operations at the same place.
Dick tries to project the problem along the initargs dimension, losing
the ability to do legality check simply( which requires a global view
of the initargs).
The basic CLOS generic function mechanism is inherently two dimensional.
We have the class hierarchy dimension and the generic function dimension.
It seems normal that we run into problems if we try to use CLOS generic
function mechanism to model a three dimensional problem.
An ad-hoc solution like moon's can ignore such constraints and can do a
better job at preserving locality and modularity.
My opinion is that we should try to go back to an ad-hoc solution, maybe
as streamlined as it needs to make everybody comfortable with, instead
of trying to force fit instance creation into generic function calling
and adding few macros on top of it.
Patrick.
∂09-Jun-87 1819 Moon@STONY-BROOK.SCRC.Symbolics.COM SETF- method names
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 9 Jun 87 18:18:47 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 168871; Tue 9-Jun-87 21:16:13 EDT
Date: Tue, 9 Jun 87 21:16 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: SETF- method names
To: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
cc: common-lisp-object-system@sail.stanford.edu
In-Reply-To: <8706041702.AA04950@hplabsc>
Message-ID: <870609211606.8.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Thu, 4 Jun 87 10:02:01 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
The CLOS spec currently says nothing about what the names of the
SETF- generic functions will be, presumably because the intent
is to encourage use of generalized variable reference.
The intent was that they would not have names at all, if I remember
correctly.
However,
since TRACE and other debugging aids require use of a function
name, lack of an easy handle for SETF- generic function names
(in the current implementation) requires that the user type in
a long, nonstandard name in order to get any debugging information.
Would it be appropriate to say anything about the SETF- generic
function name, realizing that nothing is said about such in CLtL?
Places I could see it being introduced into the spec are:
1) As an additional keyword argument to DEFGENERIC-OPTIONS-SETF,
pg. 2-24:2-25. This could be used to specify the prefix for
generating the SETF- generic function name.
You seem to be assuming that for any setf generic function, there will
be some symbol such that SYMBOL-FUNCTION of that symbol yields the setf
generic function. I don't see why. The Symbolics and TI
implementations, to take two examples, do not have any such symbols.
In addition, CLOS has some support for anonymous generic functions,
and presumably setf generic functions would be just one example of
such anonymous generic functions. I don't know how this was intended
to fit into TRACE and other debugging aids.
2) As an additional function, like GET-SETF-GENERIC-FUNCTION.
The implementation is simply:
(generic-function-name (get-setf-generic-function <name>))
but would not require the metaobject protocol function GENERIC-FUNCTION-NAME
be used.
If we're going to standardize on a way to name setf generic functions,
it should be a way to name methods as well. After all, you'd like to be
able to trace methods. I firmly believe that it should be based on the
"function spec" system used by Symbolics and TI, not on some scheme of
symbols with generated names. However in the past whenever I have
proposed "function specs" to the Common Lisp community, I got a lot of
abuse, so I'm tired of bothering.
∂09-Jun-87 1832 Moon@STONY-BROOK.SCRC.Symbolics.COM object / cleanup subcommittee interaction
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 9 Jun 87 18:32:35 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 168878; Tue 9-Jun-87 21:31:51 EDT
Date: Tue, 9 Jun 87 21:31 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: object / cleanup subcommittee interaction
To: common-lisp-object-system@SAIL.STANFORD.EDU
In-Reply-To: The message of 2 Jun 87 13:29 EDT from Dick Gabriel <RPG@SAIL.STANFORD.EDU>
Message-ID: <870609213148.0.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 02 Jun 87 1029 PDT
From: Dick Gabriel <RPG@SAIL.STANFORD.EDU>
I assumed that a generic function was a function and so could appear in
a function cell. Doesn't the Concepts chapter state that
(typep <generic function> 'function) => T
I presume that a generic function is a function under the cleaned-up
definition.
This is all true, but I think the actual issue was something else. It's
starting to come back to me: it's separating what the SYMBOL-FUNCTION
function does from what the implementation actually stores, so no one
can object on efficiency grounds. This is more of an implementation
note than a language specification.
Moon, do you know the date of your message discussing the non-keyword &key
arguments? What are the considerations?
I don't know the date, but the proposal name was KEYWORD-ARGUMENT-NAME-PACKAGE.
I'll send you the newest copy of it that I have, under separate cover (and
just to Dick).
∂09-Jun-87 1852 Moon@STONY-BROOK.SCRC.Symbolics.COM SETF- method names
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 9 Jun 87 18:52:49 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 168882; Tue 9-Jun-87 21:52:18 EDT
Date: Tue, 9 Jun 87 21:52 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: SETF- method names
To: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
cc: common-lisp-object-system@sail.stanford.edu
In-Reply-To: <8706041702.AA04950@hplabsc>
Supersedes: <870609211606.8.MOON@EUPHRATES.SCRC.Symbolics.COM>
Comments: Added comment about tracing functions rather than tracing function-names.
Message-ID: <870609215209.1.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Thu, 4 Jun 87 10:02:01 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
The CLOS spec currently says nothing about what the names of the
SETF- generic functions will be, presumably because the intent
is to encourage use of generalized variable reference.
The intent was that they would not have names at all, if I remember
correctly.
However,
since TRACE and other debugging aids require use of a function
name, lack of an easy handle for SETF- generic function names
(in the current implementation) requires that the user type in
a long, nonstandard name in order to get any debugging information.
Would it be appropriate to say anything about the SETF- generic
function name, realizing that nothing is said about such in CLtL?
Places I could see it being introduced into the spec are:
1) As an additional keyword argument to DEFGENERIC-OPTIONS-SETF,
pg. 2-24:2-25. This could be used to specify the prefix for
generating the SETF- generic function name.
You seem to be assuming that for any setf generic function, there will
be some symbol such that SYMBOL-FUNCTION of that symbol yields the setf
generic function. I don't see why. The Symbolics and TI
implementations, to take two examples, do not have any such symbols.
In addition, CLOS has some support for anonymous generic functions,
and presumably setf generic functions would be just one example of
such anonymous generic functions. I don't know how this was intended
to fit into TRACE and other debugging aids.
CLtL's discussion of TRACE is very vague, so maybe the following doesn't
belong in the standard anyway. But is there any reason why TRACE
couldn't accept functions as arguments, rather than only accepting
function names? The main limitation seems to be that TRACE is a macro
and doesn't evaluate its subforms.
2) As an additional function, like GET-SETF-GENERIC-FUNCTION.
The implementation is simply:
(generic-function-name (get-setf-generic-function <name>))
but would not require the metaobject protocol function GENERIC-FUNCTION-NAME
be used.
If we're going to standardize on a way to name setf generic functions,
it should be a way to name methods as well. After all, you'd like to be
able to trace methods. I firmly believe that it should be based on the
"function spec" system used by Symbolics and TI, not on some scheme of
symbols with generated names. However in the past whenever I have
proposed "function specs" to the Common Lisp community, I got a lot of
abuse, so I'm tired of bothering.
∂09-Jun-87 1921 Moon@STONY-BROOK.SCRC.Symbolics.COM object / cleanup subcommittee interaction
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 9 Jun 87 19:21:37 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 168903; Tue 9-Jun-87 22:21:01 EDT
Date: Tue, 9 Jun 87 22:20 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: object / cleanup subcommittee interaction
To: Common-Lisp-Object-System@sail.stanford.edu
In-Reply-To: <870602003210.7.MOON@EUPHRATES.SCRC.Symbolics.COM>,
The message of 2 Jun 87 13:29 EDT from Dick Gabriel <RPG@SAIL.STANFORD.EDU>,
<870602-114805-4200@Xerox>,
<8706022335.AA00365@hplabsc>,
<870603-113213-2135@Xerox>,
<8706032153.AA14903@hplabsc>,
<870605-234940-2970@Xerox>
Message-ID: <870609222055.2.MOON@EUPHRATES.SCRC.Symbolics.COM>
Thanks for all the input. This is the summary I came up with:
This file is a list of things that the CLOS committee would like to see
cleaned up. I have tried to keep it brief. Where proposals have been
submitted to the Cleanup committee, the proposal name is listed as
"PROPOSAL: name". Where the Cleanup committee has assigned an issue
name, but there is no proposal yet, it is listed as "ISSUE: name".
1. PROPOSAL: FUNCTION-TYPE
Making FUNCTION be a genuine type (distinct from CONS).
2. PROPOSAL: KEYWORD-ARGUMENT-NAME-PACKAGE
Allowing keyword argument indicators to be non-keyword symbols.
3. ISSUE: DEFSTRUCT-CLOS
A recommendation to design a DEFRECORD facility to replace the part
of DEFSTRUCT that is not replaced by DEFCLASS.
4. ISSUE: PATHNAME-HASH-TABLE-TYPE-DISTINCT
Mandating a bunch of types (I don't have the complete list right now)
to be disjoint from a bunch of other types (again I don't have a
complete list right now) so that they can all be made into classes
without establishing any implementation-dependent subclass relationships.
5. PROPOSAL: SHARP-COMMA-SPECIAL-FORM
(in some Cleanup documents this is called LOAD-TIME-EVAL)
A macro should be able to include in its expansion the same sort
of thing that the #, reader-macro produces, enabling load-time
evaluation.
6. ISSUE: LEXICAL-ENVIRONMENT-ACCESSORS
Providing constructors and accessors for lexical environments.
This is somehow related to or a substitute for a symbol macro
facility [I don't understand the connection --Moon]
7. (no issue name)
Implementation note: clarify that the value returned by SYMBOL-FUNCTION,
and the value accepted by SETF of SYMBOL-FUNCTION, are not necessarily
what the implementation actually stores for purposes of function calling.
Specifically, (SETF (SYMBOL-FUNCTION x) gf), where gf is a generic function,
might create compiled code for method dispatching and store it in a place
associated with x, so that a call to x will compile as a call to that
compiled code, and will never touch the generic function object. However,
even if an implementation uses this technique, (SYMBOL-FUNCTION x) must
return the value gf, not the internal compiled code. Furthermore,
(FUNCALL gf ...) must produce the correct effect; it is permissible for
it to be slower than calling the internal compiled code.
8. (no issue name)
Require (deftype quote (object) `(member ,object)) to be built-in.
9. (no issue name)
Class objects must be acceptable to TYPEP and SUBTYPEP as type-specifiers.
This is probably part of CLOS rather than anything for the Cleanup committee.
∂09-Jun-87 2044 Moon@STONY-BROOK.SCRC.Symbolics.COM I. Formal Specification of Gen. Fcn. Invocation
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 9 Jun 87 20:44:17 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 168962; Tue 9-Jun-87 23:43:37 EDT
Date: Tue, 9 Jun 87 23:43 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: I. Formal Specification of Gen. Fcn. Invocation
To: common-lisp-object-system@sail.stanford.edu
In-Reply-To: <8706091502.AA00446@hplabsc>
Message-ID: <870609234334.6.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Tue, 9 Jun 87 08:02:18 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
....I will post the results in a series of three notes which deal with
the three aspects of calculating the effective method....
I found that I was unable to comprehend any of this. I'll try again
some time when I have several hours available and no distractions.
I'm sure that the language in the document could be clearer and
less ambiguous, especially if it wasn't written by a committee, but
right now I'm not sure whether a more formal approach would make the
document easier to understand or would simply obfuscate it and end
up making errors more difficult to uncover.
1) Only one major inconsistency was found in the specification.
The requirement at the bottom of pg. 1-24 that the invocation of
CALL-NEXT-METHOD in the least specific :AROUND method would return
the effective method invocation result to the continuation (caller)
I am unable to find any such requirement. All I see is that the value
returned by the invocation of CALL-NEXT-METHOD in the least specific
:AROUND method is controlled by the most specific primary method.
Are you looking at an old version of the document perhaps?
2) The case of having two EQL specializers on the same parameter
which differ during sorting of applicable methods cannot occur.
It is forbidden by the way in which the set of applicable methods
is constructed. An ambiguous statement in the second paragraph at
the top of pg. 1-22 implies that it can, however.
This typo ("quoted" for "equal") was corrected in the corrections
handed out in March.
∂09-Jun-87 2234 kempf%hplabsc@hplabs.HP.COM Re: SETF- method names
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 22:34:10 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Tue, 9 Jun 87 22:32:55 pdt
Received: by hplabsc ; Tue, 9 Jun 87 22:31:45 pdt
Date: Tue, 9 Jun 87 22:31:45 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706100531.AA10636@hplabsc>
To: Moon@STONY-BROOK.SCRC.Symbolics.COM, kempf%hplabsc@hplabs.HP.COM
Subject: Re: SETF- method names
Cc: common-lisp-object-system@sail.stanford.edu
>If we're going to standardize on a way to name setf generic functions,
>it should be a way to name methods as well. After all, you'd like to be
>able to trace methods. I firmly believe that it should be based on the
>"function spec" system used by Symbolics and TI, not on some scheme of
>symbols with generated names. However in the past whenever I have
>proposed "function specs" to the Common Lisp community, I got a lot of
>abuse, so I'm tired of bothering.
>
Not being familiar with "function specs", I'm not in a position to
comment on them; however, I think the current situation is pretty
tenuous. As mentioned in the "Open Issues" note and subsequent
discussion, the way I usually trace SETF- functions is by macroexpanding
a form to see what the function name is. Admittedly, one could argue
this is an environmental thing, but since CLtL specifies the TRACE
function, there should be some means of doing this. Tracing methods
would also be nice. Maybe it would be best to defer this for the
moment, since it seems to be a more general problem of SETF-, and
can be solved in PCLOS/PCL (kludgily) by simply generating a more
tractable name, thus keeping my users happy.
jak
∂09-Jun-87 2349 Masinter.pa@Xerox.COM Re: object / cleanup subcommittee interaction
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 9 Jun 87 23:49:17 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 09 JUN 87 23:48:32 PDT
Date: 9 Jun 87 23:48 PDT
From: Masinter.pa@Xerox.COM
Subject: Re: object / cleanup subcommittee interaction
In-reply-to: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>'s
message of Tue, 9 Jun 87 22:20 EDT
To: Moon@STONY-BROOK.SCRC.Symbolics.COM
cc: Common-Lisp-Object-System@sail.stanford.edu
Message-ID: <870609-234832-2213@Xerox>
I'll assign a random proposal name if you like:
8) ISSUE: TYPE-MEMBER-SINGLETON (issue is that (member t) is awkward
when there's only one)
Proposal TYPE-MEMBER-SINGLETON:QUOTE
As you say, point 7 (SYMBOL-FUNCTION may not be what's stored) is
really an implementation note rather than any language specification
change. I don't see that it requires a cleanup, for that reason.
I agree that your point 9 (TYPEP takes class object) really is more part
of the CLOS than a cleanup, (Without CLOS, there are no class objects,
and the issue is moot.)
∂10-Jun-87 0934 kempf%hplabsc@hplabs.HP.COM Re: I. Formal Specification of Gen. Fcn. Invocation
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 10 Jun 87 09:33:46 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Wed, 10 Jun 87 09:32:47 pdt
Received: by hplabsc ; Wed, 10 Jun 87 09:31:14 pdt
Date: Wed, 10 Jun 87 09:31:14 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706101631.AA15389@hplabsc>
To: common-lisp-object-system@sail.stanford.edu
Subject: Re: I. Formal Specification of Gen. Fcn. Invocation
Cc: kempf%hplabsc@hplabs.HP.COM
Comments from Dave Moon:
>I'm sure that the language in the document could be clearer and
>less ambiguous, especially if it wasn't written by a committee, but
>right now I'm not sure whether a more formal approach would make the
>document easier to understand or would simply obfuscate it and end
>up making errors more difficult to uncover.
Yes, a more formal approach may make the spec require more effort to follow.
What I hoped to avoid is a case like some Common Lisp implementations,
where an implementor picks up on one or two ambiguous phrases, interprets them
in a way which the majority of the implementers interpreted differently,
and thereby makes portablility of application code a lot harder to
achieve. Additionally, with a more formal approach, I think we may have
a better chance at convincing the ISO Committee at looking favorably
on CLOS semantics (even if they don't like the syntax), and perhaps the
Scheme community as well. As far as the object subcommittee's work goes, if
the consensus is that just now is not the time to introduce more
formalism, we can defer discussion until later. I'm planning on pursuing
the problem, since I think it is an interesting and important one, but
I'll avoid posting the details and only post questions or suggested
corrections, if people prefer.
>Are you looking at an old version of the document perhaps?
I have the version which was distributed at the March ANSI meeting,
along with the corrections distributed at the same meeting. If
the on-line version on SAIL or PARCVAX has corrections beyond
those, then I need to take a look at them. We have troubles
getting FTP connections here.
Danny Bobrow's comments:
> 2) The case of having two EQL specializers on the same
> parameter which differ during sorting of applicable methods cannot
> occur.
>I read the statement on page 1-22 as a proof of this statement.
The problem is the following. On page 1-21, last paragraph, there
is a description of the sorting process:
Compare the corresponding parameter specializers. When
a pair of parameter specializers are equal, proceed to
the next pair and compare them for equality. If all
corresponding parameter specializers are equal, the two
methods must have different qualifiers; in this case, either
method can be selected to precede the other (Comment:
this is also not strictly true, since they will actually
be in the same equivalence class. One could be a :BEFORE
and the other a :AFTER method, for example. In fact,
the two methods are incomparable with regard to precedence.)
If not all corresponding parameter specializers are equal,
the first pair of parameter specializers that are not
equal determines the precedence.
At this point, we move to pg. 1-22, and I'm assuming the rest
of the section deals with how to determine precedence. Determining
precedence for class specifiers is in the next paragraph, then the second last
paragraph in the section discusses EQL precedence:
If just one parameter is (QUOTE <object>), the method
with that parameter specializer preceeds the other
method. (Comment: Here comes the condition which cannot
occur.) If both parameter specializers are quoted
objects, the specializers must be quoted objects
(otherwise the two methods would not both have been
applicable for this argument).
In fact, at this point, it is not possible for both parameter
specializers to be quoted objects, because, if a specializer is
a quoted object, it must be EQL to the actual parameter for
the method, to even be an applicable method. If it is EQL to
the actual parameter, then two methods cannot differ on that
specializer, because all methods with an EQL specializer at
that parameter position will have the same specializer.
> 1) Only one major inconsistency was found in the specification.
> The requirement at the bottom of pg. 1-24 that the invocation of
> CALL-NEXT-METHOD in the least specific :AROUND method would return
> the effective method invocation result to the continuation (caller)
> requires that CALL-NEXT-METHOD in the least specific :AROUND method
> behave fundamentally differently than in other instances. It also
> contradicts the statement in the middle of the page that the most
> specific :AROUND method provides the value for the invocation. I
> suspect it is a typo, and would suggest that the statement in the
> middle of the page prevail.
>
>You must have a different reading of the words than I do. In the middle
>of the page it says:
>* If there are any :around methods, the most specific :around method is
>called. It supplies the value for the method.
>
>At the bottom it uses the phrase "If no :around methods were invoked"
>This means that there are no :around methods. In this case, the value
>is the value returned from what I will call the "effective primary
>method" which will be the value returned by the most specific primary
>method.
I'm not arguing with the case of no :AROUND methods, but rather
with the case of a CALL-NEXT-METHOD in the least specific :AROUND
method which causes control transfer to the effective primary
method. The statement in my copy of the spec says:
Otherwise, the value or values returned by the most
specific primary method are those returned by the invocation
of CALL-NEXT-METHOD in the least specific :AROUND
method.
My reading was that the following sequence of events occurs:
generic function invocation context:
most specific :AROUND
CALL-NEXT-METHOD -----------> to next most specific
next most specific :AROUND
CALL-NEXT-METHOD------------> to next next most specific
....
in least specific :AROUND:
CALL-NEXT-METHOD -------> transfer of control to
primary method
and execution of it.
Upon completion, transfer
back to least specific
THROW to generic <------- :AROUND method
function invocation
context.
In fact, on a closer reading (and looking at the following comments
about how to construct the effective primary method), I agree
that this interpretation is faulty.
> The "effective primary method" is the method constructed
>approximately as
>(PROG2 (PROGN before1 .. beforen) primary1 (PROGN aftern ... after1))
>where index 1 is more specific method than one with 2, ...
>
>call-next-method always works on a list of effective methods, and always
>calls the next in the list. The list for standard method combination is
>
>(around1 ... aroundn effective-primary-method)
>and hence there is no difference in what call-next-method does in the
>two cases. The value is of course the value of the first method on this
>list. I am not sure I understand your statement:
> " the invocation of CALL-NEXT-METHOD in the least specific
> :AROUND method would return the effective method invocation result
> to the continuation (caller)"
>
My initial reading of the bottom of 1-24 resulted in the interpretation of
the execution sequence as listed above. This is what I meant by
the statement.
>Further in your formal description, you talk about control passing to
>the before methods, without building a construct like
>effective-primary-method. I think this is a mistake, since it loses the
>nesting of the methods, and how values are returned.
I agree. I think the concept of the effective primary method is a
good one and it clarifies the concepts. Additionally, I think my
reading of the bottom of pg. 1-24 was confused by the fact that
I was interpreting the return value of the primary method with the
the return value of the generic function, since the first sentence
of the paragraph deals with the latter, and the second with the
former. It might be helpful to seperate out these two concepts,
in language something like:
The process of generic function invocation is completed
by returning value(s) to the invocation context. If
no :AROUND methods were invoked, then the most specific
primary method supplies the value(s) returned
by the generic function. If the most specific :AROUND
method was invoked, but control transfer to the
effective primary method via CALL-NEXT-METHOD in the
least specific :AROUND method does not occur, then
the return value(s) of the most specific :AROUND method
are the value(s) returned by the generic function. If
control transfer to the effective primary method does
occur, then the value(s) returned by the effective
primary method are potentially modifiable by the
:AROUND methods, and, again, the most specific :AROUND
method supplies the return value(s) for the generic
function invocation.
In the meantime, I'll look into incorporating the idea of an
effective primary method into the formalism.
jak
∂10-Jun-87 1006 RPG CLOS Document
To: common-lisp-object-system@SAIL.STANFORD.EDU
The version of the document on SAIL has the true errata corrected.
-rpg-
∂10-Jun-87 1114 skeene@STONY-BROOK.SCRC.Symbolics.COM Concepts chapter on standard type classes
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 10 Jun 87 11:14:14 PDT
Received: from JUNCO.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 169429; Wed 10-Jun-87 14:13:43 EDT
Date: Wed, 10 Jun 87 14:13 EDT
From: Sonya E. Keene <skeene@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Concepts chapter on standard type classes
To: common-lisp-object-system@sail.stanford.edu
Message-ID: <870610141334.1.SKEENE@JUNCO.SCRC.Symbolics.COM>
Below is a proposed section to go into the Concepts part of the document.
I'll also be sending a draft section to go into the Design Rationale
part of the document.
\beginSection{Integrating Types and Classes}
The \CLOS\ maps the Common Lisp type space into the space of classes.
Every class that has a name has a corresponding type with the same
name. {\bf defclass} and {\bf defstruct} define both types and classes.
The name of every class is a valid type specifier. In addition, every
class object is a valid type specifier. Thus the expression {\tt (typep
{\it object class\/})} evaluates to true if the class of {\it object\/}
is {\it class\/} itself or a subclass of {\it class}. The evaluation of
the expression {\tt (subtypep {\it class1 class2\/})} returns the
values {\bf t t} if {\it class1\/} is a subclass of {\it class2\/} or if they
are the same class; otherwise it returns the values {\bf nil t}.
Many but not all of the predefined Common Lisp type specifiers have a
corresponding class with the same name as the type. For
example, the type {\bf array} has a corresponding class named {\bf array}.
A class that corresponds to a predefined Common Lisp type is called a
{\bit standard type class\/}. Each standard type class has the class
{\bf standard-type-class} as a metaclass. It is not allowed to make an
instance of a standard type class with {\bf make-instance} nor to include
a standard type class as a superclass of a class.
The purpose for specifying that many of the standard Common Lisp types
have a corresponding class is to allow users to write methods that
discriminate on these types. The hierarchical relationships among
the Common Lisp types are maintained by the classes corresponding to
those types. Thus the existing type hierarchy is used for determining
the class precedence lists for each standard type class.
Method selection requires that a class precedence list can be
determined for each class, ordering the class and its superclasses from
most to least specific. In some cases, {\it Common Lisp: the
Language\/} does not specify a subtype/supertype relationship for two
supertypes of a given type. For example, {\bf null} is a subtype of
{\bf symbol} and {\bf list}, but {\it Common Lisp: the Language\/} does
not specify whether {\bf symbol} is more or less specific than {\bf
list}. The \CLOS\ specification defines those relationships for all
standard type classes.
The following table lists the set of standard type classes required by
\CLOS\. The superclasses of each standard type class are presented in
order from most specific to most general:
STANDARD TYPE CLASS SUPERCLASSES
array t
bit-vector vector, array, sequence, t
character t
complex number, t
cons sequence, t
float number, t
integer rational, number, t
list cons, sequence, t
null list, cons, symbol, sequence, t
number t
ratio rational, number, t
rational number, t
sequence t
string vector, array, sequence, t
symbol t
t
vector array, sequence, t
Note that instances of standard classes are type disjoint with all other
types.
Individual implementations can allow other type specifiers to have a
corresponding class. Also individual implementations can add additional
subclass relationships as long as they do not violate {\it Common Lisp:
the Language\/}.
Creating a type by means of {\bf defstruct} also creates a class in the
space of Common Lisp classes. Such a class is an instance of {\bf
structure-class} and a direct subclass of the class that corresponds to
the included structure, if any.
No type specifier that is a list, such as {\tt (vector double-float
100)}, has a corresponding class. No type defined by {\bf deftype} has
a corresponding class.
For a discussion on some of the design decisions underlying this aspect
of \CLOS\, see the section "Design Theories of the Integration of Types
and Classes".
\endSection%{Integrating Types and Classes}
∂10-Jun-87 1117 skeene@STONY-BROOK.SCRC.Symbolics.COM Design Rationale section on standard type classes
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 10 Jun 87 11:17:11 PDT
Received: from JUNCO.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 169433; Wed 10-Jun-87 14:16:24 EDT
Date: Wed, 10 Jun 87 14:16 EDT
From: Sonya E. Keene <skeene@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Design Rationale section on standard type classes
To: common-lisp-object-system@sail.stanford.edu
Message-ID: <870610141615.2.SKEENE@JUNCO.SCRC.Symbolics.COM>
\beginSection{Design Theories of the Integration of Types and Classes}
This section explains some of the design decisions regarding the
integration of the existing Common Lisp type system with the \CLOS\
class system. For background information, see the section
``Integrating Types and Classes''.
This section answers the following questions:
\beginlist
\item{\bull} Why do some of the standard Common Lisp types have a
corresponding class?
\item{\bull} Why don't all of the standard Common Lisp types have a
corresponding class?
\item{\bull} What were the guidelines for choosing which types would
have a class, and which would not?
\endlist
Question: Why do some of the standard Common Lisp types have a
corresponding class?
The purpose for specifying that many of the standard Common Lisp types
have a corresponding class is to allow users to write methods that
discriminate on these types; this is a powerful programming tool.
The standard type specifiers fit neatly into the method selection
model, but they are not suited to the complete \CLOS\ model, with respect
to building classes from superclasses, creating instances, and changing
the class of an instance. It is useful to discuss the practical and
conceptual distinctions between standard type classes and standard
classes. (A standard class is a user-defined class.) Standard type
classes have the following restrictions:
\beginlist
\item{\bull} A standard type class cannot be used as superclasses.
The difference between standard type classes and standard classes is
in the implementation of instances. Instances of a standard type class
are implemented in a specialized way that does not permit subclassing.
In some implementations some classes documented as standard type classes
might in fact be implemented as standard classes, but portable
programs cannot assume this.
\item{\bull} {\bf make-instance} cannot be used to create an instance
of a standard type class.
The capability of using {\bf make-instance} for standard type classes
gives no extra power or utility to the programmer. Also, the \CLOS\
model does not extend gracefully in this direction. Standard
classes have slots, but standard type classes have values of other
sorts (such as the value of an integer or the elements of an array)
which do not fit the {\bf make-instance} model.
\item{\bull} You cannot change the class of an instance of a standard
type class.
The semantics of changing an instance of a standard type class are not
at all clear. This is a basic difference between standard type
classes and standard classes.
\endlist
Question: Why don't all of the standard Common Lisp types have a
corresponding class?
It would be useful to extend the standard type classes to encompass the
full generality of Common Lisp type specifiers, but this raises
theoretical issues that are not yet appropriate for standardization.
These issues include:
\beginlist
\item{\bull} Deciding what to do when an argument is an instance of two
types, both of which have methods, but neither is a subtype of the
other. Some of the types in {\it Common Lisp: the Language\/}
have no constraints on their precedence relations to other types.
\item{\bull} The types that specify subranges present similar problems.
It is unclear how to determine the relative precedence of two
subranges of the same type.
\item{\bull} Dealing with Boolean combinations, such as negation, {\bf
and}, and {\bf or} presents problems with determinging relative
precedence order. For more information, see ``Boolean Classes'' by D.
McAllester and R. Zabih, a paper presented at the 1986 ACM First Annual
Conference on Object-Oriented Programming Systems, Languages, and
Applications.
\item{\bull} Some Common Lisp type specifiers are not defined clearly
enough in {\it Common Lisp: the Language\/} to be useful as classes.
Until the specification of these types is clarified, it would be
counterproductive to have corresponding classes for the types.
\item{\bull} Some types cannot be used for discrimination, such as {\bf
nil} and {\bf values}. No object can be an instance of these types
so there is no advantage to having classes for them.
\endlist
The \CLOS\ specification intentionally leaves room for adding more
standard type classes when these issues are resolved. For example,
when and if the Common Lisp Cleanup Committee provides a relative
precedence order on the types that currently lack them, these types
could have corresponding classes. Similarly, classes could be added
for the types whose specifications are currently too vague, whenever
the types are more rigorously defined.
Question: What were the guidelines for choosing which types would
have a class, and which would not?
The general guidelines were given above. The reasons for excluding
each individual type are given here:
{\it Boolean combinations and negation:\/}
{\bf and}
{\bf atom} - Negation {\bf (not cons}}.
{\bf or}
{\bf not}
{\it Subranges:\/}
{\bf bignum}
{\bf bit}
{\bf fixnum}
{\bf keyword}
{\bf member} - Subrange, if more than one argument is given.
{\bf mod} - Subrange of {\bf integer}.
{\bf satisfies} - Unclear subtype relations.
{\bf simple-array}
{\bf simple-bit-vector}
{\bf simple-string}
{\bf simple-vector}
{\bf standard-char}
{\bf string-char}
{\it The specification of these types is too vague:\/}
{\bf common}
{\bf stream}
{\bf function}
{\bf compiled-function}:
{\it No constraints on the precedence relations to other types:\/}
{\bf package}
{\bf readtable}
{\bf random-state}
{\bf hash-table}
{\bf pathname}
{\it No object can be an instance of this type:\/}
{\bf nil}
{\bf values}
{\it The meaning and existence of these types is
implementation-dependent:\/}
{\bf short-float}
{\bf long-float}
{\bf single-float}
{\bf double-float}
\endSection%{Design Theories of the Integration of Types and Classes}
∂10-Jun-87 1412 Moon@SAPSUCKER.SCRC.Symbolics.COM Re: I. Formal Specification of Gen. Fcn. Invocation
Received: from [192.10.41.223] by SAIL.STANFORD.EDU with TCP; 10 Jun 87 14:12:08 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by SAPSUCKER.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 136747; Wed 10-Jun-87 16:45:41 EDT
Date: Wed, 10 Jun 87 16:44 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: I. Formal Specification of Gen. Fcn. Invocation
To: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
cc: common-lisp-object-system@sail.stanford.edu
In-Reply-To: <8706101631.AA15389@hplabsc>
Message-ID: <870610164436.4.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Wed, 10 Jun 87 09:31:14 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
>Are you looking at an old version of the document perhaps?
I have the version which was distributed at the March ANSI meeting,
along with the corrections distributed at the same meeting.
That's the same version that I have, so we're all right on that score.
∂10-Jun-87 1627 Bobrow.pa@Xerox.COM Re: SETF- method names
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 10 Jun 87 16:27:36 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 10 JUN 87 16:04:43 PDT
Date: 10 Jun 87 16:04 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: SETF- method names
In-reply-to: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>'s
message of Tue, 9 Jun 87 21:16 EDT
To: common-lisp-object-system@sail.stanford.edu
Message-ID: <870610-160443-1086@Xerox>
Kempf says: However,
since TRACE and other debugging aids require use of a function
name, lack of an easy handle for SETF- generic function names
(in the current implementation) requires that the user type in
a long, nonstandard name in order to get any debugging information.
Would it be appropriate to say anything about the SETF- generic
function name, realizing that nothing is said about such in CLtL?
There are two issues here.
1) SETF forms do not guarantee to call a function, and hence there is no
level of indirection one can count on to smash to build a tracing
facility.
2) With generic functions, there is such a level of indirection without
using a name, namely the generic function object. If TRACE were a
generic function that had an implementation dependent method on
GENERIC-FUNCTION, it would wqork fine. So again no names are needed.
∂10-Jun-87 2132 Moon@STONY-BROOK.SCRC.Symbolics.COM Object Creation Discussion
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 10 Jun 87 21:31:49 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 169962; Wed 10-Jun-87 23:34:53 EDT
Date: Wed, 10 Jun 87 23:34 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Object Creation Discussion
To: Common-Lisp-Object-System@sail.stanford.edu
Message-ID: <870610233442.4.MOON@EUPHRATES.SCRC.Symbolics.COM>
In case you're wondering why you haven't heard from me recently: I'm carrying around
a 70-page sheaf of printout of the recent mail on the subject, which is gradually
getting notes written on it, but I haven't reached any conclusions worth repeating yet.
∂10-Jun-87 2338 RPG
To: common-lisp-object-system@SAIL.STANFORD.EDU
Ad Hoc Solutions
Patrick has provided a good analysis of the problems with initialization.
Let me add a little more to it and then let's think about how to proceed.
Initialization is an exemplar of a category of programs, some of which
will be things that users will want to write for themselves. For example,
suppose someone wants to write a DISPLAY-INSTANCE function that will take
a number of arguments; some of those arguments will be used to
supply information for the positioning of the displayed instance, others will
alter defaults that are normally supplied by the classes in the
class precedence list, where these defaults determine how the display will
look (icons, text, texture, background colors, feature colors, sound,
animation, etc). The end-user will want to customize the display by
defining methods on generic functions that get invoked by DISPLAY-INSTANCE.
In this example, we have the problem of determining the defaults as
contributed from the classes in the class precedence list, the problem
of checking the legality of the arguments, and the problem of distributing
the arguments to the right methods.
These are the same problems as in initialization, and the programmer will
need to define his own methodology for solving them if we use an ad hoc
approach for initialization. Assuming a declarative solution, I can even
imagine a programmer using the initialization mechanism to accomplish his
needs in the DISPLAY-INSTANCE problem.
My question is: Is this category of programs large enough that we need to
work Patrick's third dimension into CLOS? Or should we admit the weakness in
CLOS, because the category is too small or is not important? I don't know the
answer to this, and all I wanted to do was explore whether or not there was
a simple way to add the functionality to CLOS so that the decision is a
no-brainer.
-rpg-
∂11-Jun-87 0746 kempf%hplabsc@hplabs.HP.COM Re: SETF- method names
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 11 Jun 87 07:46:20 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 11 Jun 87 07:46:18 pdt
Received: by hplabsc ; Thu, 11 Jun 87 07:45:01 pdt
Date: Thu, 11 Jun 87 07:45:01 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706111445.AA28326@hplabsc>
To: Bobrow.pa@Xerox.COM, common-lisp-object-system@sail.stanford.edu
Subject: Re: SETF- method names
>2) With generic functions, there is such a level of indirection without
>using a name, namely the generic function object. If TRACE were a
>generic function that had an implementation dependent method on
>GENERIC-FUNCTION, it would wqork fine. So again no names are needed.
>
A this would solve the problem nicely, for those cases where the
funcallable object is well defined (fundefs, generic functions,
symbols w. function cell bound, methods, etc.).
The problem remains with SETF forms which take generalized variable
references, like SVREF, since there is currently no way to obtain
the funcallable object corresponding to the SETF "method" (to use
CLtL terminology).
jak
∂11-Jun-87 0819 kempf%hplabsc@hplabs.HP.COM Re: Order of Initialization
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 11 Jun 87 08:19:31 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 11 Jun 87 08:17:56 pdt
Received: by hplabsc ; Thu, 11 Jun 87 08:16:39 pdt
Date: Thu, 11 Jun 87 08:16:39 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706111516.AA28670@hplabsc>
To: Bobrow.pa@Xerox.COM, kempf%hplabsc@hplabs.HP.COM
Subject: Re: Order of Initialization
Cc: Common-lisp-object-system@SAIL.STANFORD.EDU, RPG@SAIL.STANFORD.EDU
>I think one should not depend on the order.
I agree, however, there may be cases where the order does matter.
>Consider the ambiguity
>resulting from two class definitions:
>
>(defclass c1 ()
> ((x :initform (initx1))
> (y :initform (inity))))
>
>(declass c2 (c1)
> ((x :initform (initx2)))
>
>These can be in a file in either order. Which order for eveluation of
>(initx2) and (inity) do you think is correct. I can think of arguments
>for both. Further, consider
>
>(defclass c3 (c1)
> ((z :initform (initz))
> (y :initform (inity2))
> (x :initform (initx3))))
>
In this particular example, the class precedence list for C1
would be:
(C1 STANDARD-OBJECT T)
the initializer for the X slot would be INITX2, and the initializer for
the Y slot would be INITY.
For C2, the class precedence list would be:
(C2 C1 STANDARD-OBJECT T)
and, according to the rules on pg. 1-8:1-9 of 87-002 (and
provided it is decided to stick with them), the initializer
for X would be INITX2 and that for Y would be INITY. If
one uses the class precedence list to impose a global ordering
on initialization, and the lexical order within the class
to impose a local ordering, one could argue that the initialization
order INITX2, INITY would make sense.
>So my choice is 3, the user should not depend on the order.
The kind of example I'm thinking about where the order of
initialization can matter is where some global information is
propagated from one initform to the other via a special, or
initialization of one slot requires previous slots to be initialized.
Like:
(defvar *screen-file-descriptor*)
(defclass window ()
(
(file-info (open-screen-file))
...
)
)
and initialization of the rest of the slots requires the special to
be bound.
I think that if the INITIALIZE-INSTANCE (or whatever is
ultimately agreed to be the name) user customizable method could be
designated the right place to put special initialization needs,
like the requirement for initialization to proceed in a particular
order, then the need for specifying the order within the class
itself goes away. However, it is important that the spec specifically
state that the user cannot depend on the order of initialization
for :INITFORMs, otherwise, someone is bound to do so.
jak
∂11-Jun-87 1120 Moon@STONY-BROOK.SCRC.Symbolics.COM Re: SETF- method names
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 11 Jun 87 11:03:38 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 170333; Thu 11-Jun-87 14:02:24 EDT
Date: Thu, 11 Jun 87 14:02 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: SETF- method names
To: common-lisp-object-system@sail.stanford.edu
In-Reply-To: <8706111445.AA28326@hplabsc>
Message-ID: <870611140213.8.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Thu, 11 Jun 87 07:45:01 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
>2) With generic functions, there is such a level of indirection without
>using a name, namely the generic function object. If TRACE were a
>generic function that had an implementation dependent method on
>GENERIC-FUNCTION, it would wqork fine. So again no names are needed.
>
Actually this opens its own can of worms. I can't figure out from CLtL
whether TRACE is intended to be an operation on function names, or on
functions. Perhaps it is intentionally left to the discretion of the
particular programming environment. All I know is that in Maclisp and
Zetalisp it was defined to be an operation on function names; but making
it operate on generic-function and method objects would make it an
operation on functions. Here's an example to show what I mean by the
distinction:
(defun foo (x) (print x))
(let ((f (function foo)))
(trace foo)
(funcall f 105))
If TRACE is an operation on function names, this just prints 105. If it's
an operation on functions, it generates tracing output as well.
A this would solve the problem nicely, for those cases where the
funcallable object is well defined (fundefs, generic functions,
symbols w. function cell bound, methods, etc.).
The problem remains with SETF forms which take generalized variable
references, like SVREF, since there is currently no way to obtain
the funcallable object corresponding to the SETF "method" (to use
CLtL terminology).
You actually mean the funcallable object called by the form that is
returned by the SETF "method"; those type of SETF-"methods" are macros,
unlike CLOS setf-methods, which are functions.
Yes, this is a problem and I don't know of any good answers to it; after
all, the SETF form might well expand into a call to a different function
depending on seemingly minor variations in details of the arguments.
Not a problem for CLOS, just a problem for CL. Your technique of
macroexpanding a sample form and assuming that the function that appears
there is the one that is going to be called is probably as good as any.
∂11-Jun-87 1243 kempf%hplabsc@hplabs.HP.COM Re: SETF- method names
Received: from HPLABS.HP.COM by SAIL.STANFORD.EDU with TCP; 11 Jun 87 12:42:47 PDT
Received: from hplabsc by hplabs.HP.COM with TCP ; Thu, 11 Jun 87 12:41:51 pdt
Received: by hplabsc ; Thu, 11 Jun 87 12:40:41 pdt
Date: Thu, 11 Jun 87 12:40:41 pdt
From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
Message-Id: <8706111940.AA02450@hplabsc>
To: Moon@STONY-BROOK.SCRC.Symbolics.COM,
common-lisp-object-system@sail.stanford.edu
Subject: Re: SETF- method names
> Date: Thu, 11 Jun 87 07:45:01 pdt
> From: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>
>
> >2) With generic functions, there is such a level of indirection without
> >using a name, namely the generic function object. If TRACE were a
> >generic function that had an implementation dependent method on
> >GENERIC-FUNCTION, it would wqork fine. So again no names are needed.
> >
>
>Actually this opens its own can of worms. I can't figure out from CLtL
>whether TRACE is intended to be an operation on function names, or on
>functions. Perhaps it is intentionally left to the discretion of the
>particular programming environment. All I know is that in Maclisp and
>Zetalisp it was defined to be an operation on function names; but making
>it operate on generic-function and method objects would make it an
>operation on functions. Here's an example to show what I mean by the
>distinction:
>
>(defun foo (x) (print x))
>(let ((f (function foo)))
> (trace foo)
> (funcall f 105))
>
>If TRACE is an operation on function names, this just prints 105. If it's
>an operation on functions, it generates tracing output as well.
>
True, it could complicate implementations. The typical way of dealing
with tracing via names is to wrap the fundef with a wrapper function,
and hang the wrapper off the symbol's function cell. This doesn't demand
anything special of the fundef or symbol, since symbols are typically
writable. If TRACE becomes an operation on fundefs, it's got to modify
the fundef object, perhaps (extrapolating from the implementation
I'm aware of) putting a jump to the trace function as the first instruction
in the fundef. This may get difficult, if fundefs are in restricted
parts of memory, like nonwritable, which often is used for sharing
executable code between processes in different address spaces (again,
in the implementation I know best).
jak
∂12-Jun-87 1002 @RELAY.CS.NET:DUSSUD%Jenner@TI-CSL.CSNET Metaclass Protocol
Received: from RELAY.CS.NET by SAIL.STANFORD.EDU with TCP; 12 Jun 87 10:02:05 PDT
Received: from relay2.cs.net by RELAY.CS.NET id ad01370; 12 Jun 87 12:54 EDT
Received: from ti-csl by RELAY.CS.NET id ag22147; 12 Jun 87 12:49 EDT
Received: by tilde id AA18373; Fri, 12 Jun 87 11:11:18 CDT
Message-Id: <2759501598-3981583@Jenner>
Date: Fri, 12 Jun 87 11:13:18 CDT
From: Patrick H Dussud <DUSSUD%Jenner%ti-csl.csnet@RELAY.CS.NET>
To: common-lisp-object-system@SAIL.STANFORD.EDU
Subject: Metaclass Protocol
This message is a first-cut attempt at a design rationale for the
metaclass protocol. The metaclass protocol being quite large, it will
be easier if we discuss and agree on the design rationale first.
We want to standardize the metaclass protocol to meet these objectives:
- Allow for portable compatible extensions to the CLOS model.
1)Some might change the instances representation/behavior while
retaining a compatible top-level interface; Persistent objects systems
and Distributed objects systems are some examples.
2)Some might extend the model by changing the classes behavior like
Delegation instead of Inheritance or they can implement another object
system for backward compatibility reasons (like Flavors, Common
Objects...). It would be desirable to allow a certain degree of
coexistence between classes belonging to different metaclasses.
- Allow for generic high level tools(Inspectors, generators, analyzers).
As a number of extensions will become available, there will be a need
for a single set of tools able to deal equally well with those
extensions.
Requirements:
The metaclass protocol should allow the implementation to pick the best
optimization strategy (in terms of code generation and instance
representation).
The metaclass protocol should allow for any programming development
styles. The idea is that an implementation should be able to support
both smooth incremental development and efficient wholesale file
compilation.
The metaclass protocol should support first class objects and anonymous
generic functions.
- Class behavior and instance behavior are othorgonal in CLOS. The
metaclass protocol must preserve this orthoganality. The metaclass
protocol should be as modular as possible. I would want to be able to
write a Persistent-mixin metaclass and then mix it with STANDARD-CLASS
to get a persistent standard-class or with FLAVORS to get a persistent
flavors metaclass, instead of having to implement a full-blown metaclass
for every case.
I think those objectives and requirements open up some specific issues:
- The side effects on CLOS objects (Classes, generic-functions, methods)
that spead across object links should be exposed.
Compute-class-precedence-list is a good example.
- It should be possible to access some exposed slots of a CLOS object
without side-effect. An inspector may need to access the
Class-precedence-list slot of a class without triggering
compute-class-precedence-list on the class. I think that means we need
to have a way to indicate when a slot contains valid data.
- We probably need to care about the compile environment. We don't have
to specify what it is but where, in our protocol it should be looked up
or side effected. At least we must make sure that we don't go against
the following statements:
1)Compile-file does not side effect the running environment.
2)It is possible to implement a cross loader (Something that loads files
in order to make some class definitions, etc that will affect
the compilation but not the running environment).
The list of requirement and issues is far from being complete, but it
probably covers enough to get the discussion started.
Patrick.
∂12-Jun-87 1204 Bobrow.pa@Xerox.COM Re: Order of Initialization
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 12 Jun 87 12:04:07 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 12 JUN 87 11:38:02 PDT
Date: 12 Jun 87 11:37 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Order of Initialization
In-reply-to: Jim Kempf <kempf%hplabsc@hplabs.HP.COM>'s message of Thu,
11 Jun 87 08:16:39 pdt
To: Common-lisp-object-system@SAIL.STANFORD.EDU, RPG@SAIL.STANFORD.EDU
Message-ID: <870612-113802-1764@Xerox>
I think that if the INITIALIZE-INSTANCE (or whatever is
ultimately agreed to be the name) user customizable method could be
designated the right place to put special initialization needs,
like the requirement for initialization to proceed in a particular
order, then the need for specifying the order within the class
itself goes away. However, it is important that the spec
specifically state that the user cannot depend on the order of
initialization for :INITFORMs, otherwise, someone is bound to do so.
RIGHT (Meaning I agree)
∂15-Jun-87 1118 Gregor.pa@Xerox.COM new new initialization protocol blues
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 15 Jun 87 11:17:55 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 15 JUN 87 11:06:40 PDT
Date: 15 Jun 87 11:06 PDT
From: Gregor.pa@Xerox.COM
Subject: new new initialization protocol blues
To: Common-Lisp-Object-System@Sail.Stanford.edu
cc: Bobrow.pa@Xerox.COM, Gregor.pa@Xerox.COM
Message-ID: <870615-110640-1411@Xerox>
Here is another example of a fully procedural initialization protocol.
This message also includes an example of using that protocol to solve
the x-y-rho-theta problem.
In this protocol, make-instance, compute-initargs,
class-default-initargs and class-legal-initargs are documented generic
functions.
The method for make-instance on standard-class is documented to call
compute-initargs and allocate-instance. The method for
allocate-instance on standard-class is documented to allocate storage
and evluate and store all the initforms. The method for
compute-initargs on object is documented to call class-default-initargs
and class-legal-initargs and do the kind of defaulting we have all come
to expect.
Many users will just want to define methods on class-default-initargs
and class-legal-initargs. Users trying to deal with problems like the
x-y-rho-theta problem will usually have to define methods on
compute-initargs as well.
(defmethod make-instance ((class symbol) &rest supplied-initargs)
(apply #'make-instance (class-named symbol) supplied-initargs))
(defmethod make-instance ((class standard-class) &rest
supplied-initargs)
(let* ((proto (class-prototype class))
(total-initargs (compute-initargs proto supplied-initargs))
(instance (apply #'allocate-instance class total-initargs)))
(apply #'initialize-instance instance total-initargs)
instance))
(defmethod compute-initargs ((object object) supplied-initargs)
(let* ((default (class-default-initargs object))
(legal (class-legal-initargs object))
(total supplied-initargs)
(magic-value (list nil)))
(do ((prop default (cddr prop))
(val (cdr default) (cddr val)))
((null prop))
(when (eq (getf total prop magic-value) magic-value)
(push (eval val) total)
(push prop total)))
(do ((prop total (cddr prop)))
((null prop))
(unless (member prop legal)
(error "~S is not a legal initarg for the class ~S"
prop
(class-of object))))
total))
(defgeneric-options class-legal-initargs (class)
(:method-comination-type append))
(defmethod class-legal-initargs ((class object)) '(:allow-other-keys))
(defgeneric-options class-default-initargs (class)
(:method-combination-type append))
(defmethod class-default-initargs ((class object)) ())
;;;
;;; Here is an example of all this in use to solve the notorious
;;; x-y-rho-theta problem.
;;; We define a class named position, which can be mixed into
;;; a class that implements either x-y-position primitives or
;;; rho-theta-position primitives. This class takes care of providing
;;; the other set of primitives, and more importantly takes care of
;;; handling the :x :y :rho :theta defaulting properly.
;;;
(defclass position () ())
(defmethod class-legal-initargs ((pos position))
'(:rho :theta :x :y))
(defmethod class-default-initargs ((pos position))
'((:x 0) (:y 0) (:rho 0) (:theta 0)))
(defmethod compute-initargs ((pos position) supplied)
(let ((x-p (memq ':x supplied))
(y-p (memq ':y supplied))
(r-p (memq ':rho supplied))
(t-p (memq ':theta supplied))
(defaults (class-default-initargs class)))
(when (and (or x-p y-p) (or r-p t-p))
(error "make up your mind loser"))
(cond ((and x-p y-p))
((and r-p t-p))
(x-p
(setf (getf supplied :y)
(eval-default-initarg (getf defaults :y))))
(y-p
(setf (getf supplied :x)
(eval-default-initarg (getf defaults :x))))
(r-p
(setf (getf supplied :theta)
(eval-default-initarg (getf defaults :theta))))
(t-p
(setf (getf supplied :rho)
(eval-default-initarg (getf defaults :rho)))))
(call-next-method pos supplied)))
(defmethod x-position ((p position))
(convert-rho-theta-to-x (rho-position p)
(theta-position p)))
(defmethod y-position ((p position))
(convert-rho-theta-to-y (rho-position p)
(theta-position p)))
(defmethod rho-position ((p position))
(convert-x-y-to-rho (x-position p)
(y-position p)))
(defmethod theta-position ((p position))
(convert-x-y-to-theta (x-position p)
(y-position p)))
(defclass x-y-position (position) (x y))
(defmethod initialize-instance :after
((pos x-y-position) &key x y &allow-other-keys)
(setf (slot-value pos 'x) x
(slot-value pos 'y) y))
(defclass rho-theta-position (position) (rho theta))
(defmethod initialize-instance :after
((pos rho-theta-position) &key rho theta &allow-other-keys)
(setf (slot-value pos 'rho) rho
(slot-value pos 'theta) theta))
∂15-Jun-87 1920 Bobrow.pa@Xerox.COM Re: new new initialization protocol blues
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 15 Jun 87 19:20:30 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 15 JUN 87 15:06:21 PDT
Date: 15 Jun 87 15:06 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: new new initialization protocol blues
In-reply-to: Gregor.pa's message of 15 Jun 87 11:06 PDT
To: Gregor.pa@Xerox.COM
cc: Common-Lisp-Object-System@Sail.Stanford.edu, Bobrow.pa@Xerox.COM
Message-ID: <870615-150621-108@Xerox>
1) It is useful to be able to allocate storage for an instance without
having to evaluate all the initforms, for example, to build a
class-prototype without risking an error. Either this must be a
function that is called by allocate-instance, or it can be the job of
allocate instance. But in Gregor's message (and my earlier message) we
stated that
The method for allocate-instance on standard-class is
documented to allocate storage and evaluate and store all the
initforms.
A useful alternative may be to make the method for allocate-instance
only allocate storage for the instance. Then the primary method on
object for initialize-instance would be documented to evaluate and store
all the initforms.
2) Gregor's method not only exposes the proposed implementation of
initargs as methods, but suggests that the user must program using this
verbose style. Here is a useful macro, shown only in an example, that
would usually be used by users to specify how to handle inputs to
specify slot-values. The name of the macro can obviously be improved.
User-code:
(define-initialize-instance-after-method x-y-position (pos &key
start-the-engine)
((x :x number "a number") ;; initialize x a slot, checking its
type as a number
(y :second) ;; initialize y as a slot, using
keyword :second
z) ;; initialize z as a slot, using z as
the keyword
(when start-the-engine (fire-up pos))) ;; other user init code
----
Translation:
(defmethod initialize-instance :after
((pos x-y-position) &key start-the-engine
((:x #:g1) nil #:g2)
((:y #:g3) nil #:g4)
((z #:g5) nil #:g6)
&allow-other-keys)
(when #:g2
(check-type #:g1 number "a number")
(setf (slot-value pos 'x) #:g1))
(when #:g4
(setf (slot-value pos 'y) #:g3))
(when #:g6
(check-type #:g5 z-type) ;; this here if :type specified
in the class
(setf (slot-value pos 'z) #:g5))
;; Now comes the user-supplied body.
(when start-the-engine (fire-up pos)))